From d2a431e6f3f9c30be4e2b91d7f89df2c846d6834 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 19 Oct 2018 14:29:51 +0200 Subject: [PATCH 1/8] C#: Add more nullness tests Port many of the nullness test from Java, as well as add new tests. --- csharp/ql/test/query-tests/Nullness/A.cs | 320 ++------ csharp/ql/test/query-tests/Nullness/Assert.cs | 46 +- csharp/ql/test/query-tests/Nullness/B.cs | 77 ++ csharp/ql/test/query-tests/Nullness/C.cs | 275 +++++++ csharp/ql/test/query-tests/Nullness/D.cs | 414 ++++++++++ csharp/ql/test/query-tests/Nullness/E.cs | 271 +++++++ .../test/query-tests/Nullness/Forwarding.cs | 14 +- .../query-tests/Nullness/GuardedString.cs | 18 +- .../Nullness/Implications.expected | 747 ++++++++++++++++++ .../test/query-tests/Nullness/Implications.ql | 6 + .../query-tests/Nullness/NullAlways.expected | 37 +- .../query-tests/Nullness/NullCheck.expected | 235 ++++++ .../ql/test/query-tests/Nullness/NullCheck.ql | 5 + .../query-tests/Nullness/NullMaybe.expected | 46 +- .../Nullness/StringConcatenation.cs | 8 +- 15 files changed, 2190 insertions(+), 329 deletions(-) create mode 100644 csharp/ql/test/query-tests/Nullness/B.cs create mode 100644 csharp/ql/test/query-tests/Nullness/C.cs create mode 100644 csharp/ql/test/query-tests/Nullness/D.cs create mode 100644 csharp/ql/test/query-tests/Nullness/E.cs create mode 100644 csharp/ql/test/query-tests/Nullness/Implications.expected create mode 100644 csharp/ql/test/query-tests/Nullness/Implications.ql create mode 100644 csharp/ql/test/query-tests/Nullness/NullCheck.expected create mode 100644 csharp/ql/test/query-tests/Nullness/NullCheck.ql diff --git a/csharp/ql/test/query-tests/Nullness/A.cs b/csharp/ql/test/query-tests/Nullness/A.cs index 41eeec03e96..62395386aea 100644 --- a/csharp/ql/test/query-tests/Nullness/A.cs +++ b/csharp/ql/test/query-tests/Nullness/A.cs @@ -2,222 +2,66 @@ using System; class A { - public void notTest() + public void Lock() { - object not_ok = null; - if (!(!(!(not_ok == null)))) + object synchronizedAlways = null; + lock (synchronizedAlways) // BAD (always) { - not_ok.GetHashCode(); - } - object not = null; - if (!(not != null)) - { - not.GetHashCode(); - } - } - public void instanceOf() - { - object instanceof_ok = null; - if (instanceof_ok is string) - { - instanceof_ok.GetHashCode(); + synchronizedAlways.GetHashCode(); // GOOD } } - public void locked() + public void ArrayAssignTest() { - object synchronized_always = null; - lock (synchronized_always) - { - synchronized_always.GetHashCode(); - } + int[] arrayNull = null; + arrayNull[0] = 10; // BAD (always) + + int[] arrayOk; + arrayOk = new int[10]; + arrayOk[0] = 42; // GOOD } - public void assignIf() + public void Access() { - string xx; - string ok = null; - if ((ok = (xx = null)) == null || ok.Length == 0) - { - } - } - public void assignIf2() - { - string ok2 = null; - if (foo(ok2 = "hello") || ok2.Length == 0) - { - } - } - public void assignIfAnd() - { - string xx; - string ok3 = null; - if ((xx = (ok3 = null)) != null && ok3.Length == 0) - { - } + int[] arrayAccess = null; + string[] fieldAccess = null; + object methodAccess = null; + object methodCall = null; + + Console.WriteLine(arrayAccess[1]); // BAD (always) + Console.WriteLine(fieldAccess.Length); // BAD (always) + Func tmp = methodAccess.ToString; // BAD (always) + Console.WriteLine(methodCall.ToString()); // BAD (always) + + Console.WriteLine(arrayAccess[1]); // GOOD + Console.WriteLine(fieldAccess.Length); // GOOD + tmp = methodAccess.ToString; // GOOD + Console.WriteLine(methodCall.ToString()); // GOOD } - - public bool foo(string o) { return false; } - - public void dowhile() + public void OutOrRef() { - string do_ok = ""; - do - { - Console.WriteLine(do_ok.Length); - do_ok = null; - } - while (do_ok != null); + object varOut = null; + TestMethod1(out varOut); + varOut.ToString(); // GOOD + object varRef = null; + TestMethod2(ref varRef); + varRef.ToString(); // BAD (always) (false negative) - string do_always = null; - do - { - Console.WriteLine(do_always.Length); - do_always = null; - } - while (do_always != null); - - string do_maybe1 = null; - do - { - Console.WriteLine(do_maybe1.Length); - } - while (do_maybe1 != null); - - string do_maybe = ""; - do - { - Console.WriteLine(do_maybe.Length); - do_maybe = null; - } - while (true); + varRef = null; + TestMethod3(ref varRef); + varRef.ToString(); // GOOD } - public void while_() - { - string while_ok = ""; - while (while_ok != null) - { - Console.WriteLine(while_ok.Length); - while_ok = null; - } - - bool TRUE = true; - string while_always = null; - while (TRUE) - { - Console.WriteLine(while_always.Length); - while_always = null; - - } - - - string while_maybe = ""; - while (true) - { - Console.WriteLine(while_maybe.Length); - while_maybe = null; - } - - } - - public void array_assign_test() - { - int[] array_null = null; - array_null[0] = 10; - - int[] array_ok; - array_ok = new int[10]; - array_ok[0] = 42; - } - - public void if_() - { - string if_ok = ""; - if (if_ok != null) - { - Console.WriteLine(if_ok.Length); - if_ok = null; - } - - - string if_always = null; - if (if_always == null) - { - Console.WriteLine(if_always.Length); - if_always = null; - } - - string if_maybe = ""; - if (if_maybe != null && if_maybe.Length % 2 == 0) - { - if_maybe = null; - } - Console.WriteLine(if_maybe.Length); - } - - public void for_() - { - string for_ok; - for (for_ok = ""; for_ok != null; for_ok = null) - { - Console.WriteLine(for_ok.Length); - } - - Console.WriteLine(for_ok.Length); - - - for (string for_always = null; for_always == null; for_always = null) - { - Console.WriteLine(for_always.Length); - } - - - for (string for_maybe = ""; ; for_maybe = null) - { - Console.WriteLine(for_maybe.Length); - } - } - - public void access() - { - int[] arrayaccess = null; - string[] fieldaccess = null; - Object methodaccess = null; - Object methodcall = null; - - Console.WriteLine(arrayaccess[1]); - Console.WriteLine(fieldaccess.Length); - Func tmp = methodaccess.ToString; - Console.WriteLine(methodcall.ToString()); - - Console.WriteLine(arrayaccess[1]); - Console.WriteLine(fieldaccess.Length); - tmp = methodaccess.ToString; - Console.WriteLine(methodcall.ToString()); - } - - public void out_or_ref() - { - object var_out = null; - TestMethod1(out var_out); - Console.WriteLine(var_out.ToString()); - - object var_ref = null; - TestMethod2(ref var_ref); - Console.WriteLine(var_ref.ToString()); - } - - public void lambda_test() + public void LambdaTest() { string actual = null; MyDelegate fun = e => x => actual = e; fun("hello")("world"); - Console.WriteLine(actual.Length); + Console.WriteLine(actual.Length); // GOOD } static void TestMethod1(out object num) @@ -229,85 +73,11 @@ class A { } - static void Main() { } -} -public delegate MyDelegate2 MyDelegate(string e); -public delegate void MyDelegate2(string e); - -class B -{ - public void operatorCall() - { - B eq_call_always = null; - B b2 = null; - B b3 = null; - B neq_call_always = null; - - if (eq_call_always == null) - Console.WriteLine(eq_call_always.ToString()); - - if (b2 != null) - Console.WriteLine(b2.ToString()); - - if (b3 == null) { } - else - Console.WriteLine(b3.ToString()); - - if (neq_call_always != null) { } - else - Console.WriteLine(neq_call_always.ToString()); - - - - } - public static bool operator ==(B b1, B b2) - { - return Object.Equals(b1, b2); - } - public static bool operator !=(B b1, B b2) - { - return !(b1 == b2); - } -} -public struct CoOrds -{ - public int x, y; - - - public CoOrds(int p1, int p2) - { - x = p1; - y = p2; - } -} - -public class Casts -{ - void test() - { - object o = null; - if ((object)o != null) - { - // GOOD - var eq = o.Equals(o); - } - } -} - -public class Delegates -{ - delegate void Del(); - - class Foo - { - public static void Run(Del d) { } - public void Bar() { } - } - - void F() - { - Foo foo = null; - Foo.Run(delegate { foo = new Foo(); }); - foo.Bar(); - } + static void TestMethod3(ref object num) + { + num = 42; + } + + public delegate MyDelegate2 MyDelegate(string e); + public delegate void MyDelegate2(string e); } diff --git a/csharp/ql/test/query-tests/Nullness/Assert.cs b/csharp/ql/test/query-tests/Nullness/Assert.cs index a389a62b156..c483d1f36d3 100644 --- a/csharp/ql/test/query-tests/Nullness/Assert.cs +++ b/csharp/ql/test/query-tests/Nullness/Assert.cs @@ -4,35 +4,51 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; class AssertTests { - void Fn() + void Fn(bool b) { - string s = null; + string s = b ? null : ""; Debug.Assert(s != null); - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD - s = null; + s = b ? null : ""; Assert.IsNull(s); - Console.WriteLine(s.Length); // always null + Console.WriteLine(s.Length); // BAD (always) - s = null; + s = b ? null : ""; Assert.IsNotNull(s); - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD - s = null; + s = b ? null : ""; Assert.IsTrue(s == null); - Console.WriteLine(s.Length); // always null + Console.WriteLine(s.Length); // BAD (always) - s = null; + s = b ? null : ""; Assert.IsTrue(s != null); - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD - s = null; + s = b ? null : ""; Assert.IsFalse(s != null); - Console.WriteLine(s.Length); // always null + Console.WriteLine(s.Length); // BAD (always) - s = null; + s = b ? null : ""; Assert.IsFalse(s == null); - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD + + s = b ? null : ""; + Assert.IsTrue(s != null && b); + Console.WriteLine(s.Length); // GOOD + + s = b ? null : ""; + Assert.IsFalse(s == null || b); + Console.WriteLine(s.Length); // GOOD + + s = b ? null : ""; + Assert.IsTrue(s == null && b); + Console.WriteLine(s.Length); // BAD (always) + + s = b ? null : ""; + Assert.IsFalse(s != null || b); + Console.WriteLine(s.Length); // BAD (always) } } diff --git a/csharp/ql/test/query-tests/Nullness/B.cs b/csharp/ql/test/query-tests/Nullness/B.cs new file mode 100644 index 00000000000..0649a901277 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/B.cs @@ -0,0 +1,77 @@ +using System; + +class B +{ + public void OperatorCall() + { + B eqCallAlways = null; + B b2 = null; + B b3 = null; + B neqCallAlways = null; + + if (eqCallAlways == null) + eqCallAlways.ToString(); // BAD (always) + + if (b2 != null) + b2.ToString(); // GOOD + + if (b3 == null) { } + else + b3.ToString(); // GOOD + + if (neqCallAlways != null) { } + else + neqCallAlways.ToString(); // BAD (always) + } + + public static bool operator ==(B b1, B b2) + { + return Object.Equals(b1, b2); + } + + public static bool operator !=(B b1, B b2) + { + return !(b1 == b2); + } + + public struct CoOrds + { + public int x, y; + + public CoOrds(int p1, int p2) + { + x = p1; + y = p2; + } + } + + public class Casts + { + void test() + { + object o = null; + if ((object)o != null) + { + var eq = o.Equals(o); // GOOD + } + } + } + + public class Delegates + { + delegate void Del(); + + class Foo + { + public static void Run(Del d) => d(); + public void Bar() { } + } + + void F() + { + Foo foo = null; + Foo.Run(delegate { foo = new Foo(); }); + foo.Bar(); // GOOD + } + } +} diff --git a/csharp/ql/test/query-tests/Nullness/C.cs b/csharp/ql/test/query-tests/Nullness/C.cs new file mode 100644 index 00000000000..0260ec10273 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/C.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +public class C +{ + public void NotTest() + { + object o = null; + if (!(!(!(o == null)))) + { + o.GetHashCode(); // GOOD + } + + if (!(o != null)) + { + o.GetHashCode(); // BAD (always) + } + } + + public void AssertNull(object o) + { + if (o != null) + throw new Exception("not null"); + } + + static bool IsNull(object o) => o == null; + + static bool IsNotNull(object o) => o != null; + + public void AssertNonNull(object o) + { + if (o == null) + throw new Exception("null"); + } + + public void AssertTest() + { + var s = Maybe() ? null : ""; + Debug.Assert(s == null); + s.ToString(); // BAD (always) + + s = Maybe() ? null : ""; + Debug.Assert(s != null); + s.ToString(); // GOOD + } + + public void AssertNullTest() + { + var o1 = new object(); + AssertNull(o1); + o1.ToString(); // BAD (always) (false negative) + + var o2 = Maybe() ? null : ""; + Assert.IsNull(o2); + o2.ToString(); // BAD (always) + } + + public void AssertNotNullTest() + { + var o1 = Maybe() ? null : new object(); + AssertNonNull(o1); + o1.ToString(); // GOOD (false positive) + + var o2 = Maybe() ? null : new object(); + AssertNonNull(o1); + o2.ToString(); // BAD (maybe) + + var o3 = Maybe() ? null : new object(); + Assert.IsNotNull(o3); + o3.ToString(); // GOOD + } + + public void TestNull() + { + object o = null; + if (IsNotNull(o)) + o.ToString(); // GOOD + + + if (!IsNull(o)) + o.ToString(); // GOOD + } + + public void InstanceOf() + { + object o = null; + if (o is string) + o.ToString(); // GOOD + } + + public void Lock() + { + var o = Maybe() ? null : new object(); + lock (o) // BAD (maybe) + o.ToString(); // GOOD + } + + public void Foreach(IEnumerable list) + { + if (Maybe()) + list = null; + foreach (var x in list) // BAD (maybe) (false negative) + { + x.ToString(); // GOOD + list.ToString(); // GOOD + } + } + + public void Conditional() + { + string colours = null; + var colour = colours == null || colours.Length == 0 ? "Black" : colours.ToString(); // GOOD + } + + public void Simple() + { + string[] children = null; + var comparator = ""; + if (children == null) + children = new string[0]; + if (children.Length > 1) { } // GOOD + } + + public void AssignIf() + { + string xx; + String ok = null; + if ((ok = (xx = null)) == null || ok.Length > 0) // GOOD + ; + } + + public void AssignIf2() + { + bool Foo(string o) => false; + string ok2 = null; + if (Foo(ok2 = "hello") || ok2.Length > 0) // GOOD + ; + } + + public void AssignIfAnd() + { + string xx; + string ok3 = null; + if ((xx = (ok3 = null)) != null && ok3.Length > 0) // GOOD + ; + } + + public void DoWhile() + { + var s = ""; + do + { + s.ToString(); // GOOD + s = null; + } + while (s != null); + + s = null; + do + { + s.ToString(); // BAD (always) + s = null; + } + while (s != null); + + s = null; + do + { + s.ToString(); // BAD (always) (reported as maybe) + } + while (s != null); + + s = ""; + do + { + s.ToString(); // BAD (maybe) + s = null; + } + while (true); + } + + public void While() + { + var s = ""; + while (s != null) + { + s.ToString(); // GOOD + s = null; + } + + var b = true; + s = null; + while (b) + { + s.ToString(); // BAD (always) + s = null; + } + + s = ""; + while (true) + { + s.ToString(); // BAD (maybe) + s = null; + } + } + + public void If() + { + var s = Maybe() ? null : ""; + if (s != null) + { + s.ToString(); // GOOD + s = null; + } + + if (s == null) + s.ToString(); // BAD (always) + + s = ""; + if (s != null && s.Length % 2 == 0) + s = null; + s.ToString(); // BAD (maybe) + } + + public void For() + { + String s; + for (s = ""; s != null; s = null) + { + s.ToString(); // GOOD + } + s.ToString(); // BAD (always) + + for (s = null; s == null; s = null) + { + s.ToString(); // BAD (always) + } + + for (s = ""; ; s = null) + { + s.ToString(); // BAD (maybe) + } + } + + public void ArrayAssignTest() + { + int[] a = null; + a[0] = 10; // BAD (always) + + a = new int[10]; + a[0] = 42; // GOOD + } + + public void Access() + { + int[] ia = null; + string[] sa = null; + + ia[1] = 0; // BAD (always) + var temp = sa.Length; // BAD (always) + + ia[1] = 0; // BAD (always), but not first + temp = sa.Length; // BAD (always), but not first + } + + bool m; + C(bool m) + { + this.m = m; + } + + bool Maybe() => this.m; +} diff --git a/csharp/ql/test/query-tests/Nullness/D.cs b/csharp/ql/test/query-tests/Nullness/D.cs new file mode 100644 index 00000000000..55ac9de6ab5 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/D.cs @@ -0,0 +1,414 @@ +using System; +using System.Diagnostics; + +public class D +{ + private bool maybe; + public bool flag; + public D(bool b, bool f) + { + this.maybe = b; + this.flag = f; + } + + public void Caller() + { + Callee1(new object()); + Callee1(null); + Callee2(new object()); + } + + public void Callee1(object param) + { + param.ToString(); // BAD (maybe) (false negative) + } + + public void Callee2(object param) + { + if (param != null) + { + param.ToString(); // GOOD + } + param.ToString(); // BAD (maybe) (false negative) + } + + private static bool CustomIsNull(object x) + { + if (x is string) return false; + if (x == null) return true; + return x == null; + } + + public void NullGuards() + { + var o1 = maybe ? null : new object(); + if (o1 != null) o1.ToString(); // GOOD + + var o2 = maybe ? null : ""; + if (o2 is string) o2.ToString(); // GOOD + + object o3 = null; + if ((o3 = maybe ? null : "") != null) + o3.ToString(); // GOOD + + var o4 = maybe ? null : ""; + if ((2 > 1 && o4 != null) != false) + o4.ToString(); // GOOD + + var o5 = (o4 != null) ? "" : null; + if (o5 != null) + o4.ToString(); // GOOD (false positive) + if (o4 != null) + o5.ToString(); // GOOD (false positive) + + var o6 = maybe ? null : ""; + if (!CustomIsNull(o6)) + o6.ToString(); // GOOD + + var o7 = maybe ? null : ""; + var ok = o7 != null && 2 > 1; + if (ok) + o7.ToString(); // GOOD + else + o7.ToString(); // BAD (maybe) + + var o8 = maybe ? null : ""; + int track = o8 == null ? 42 : 1 + 1; + if (track == 2) + o8.ToString(); // GOOD (false positive) + if (track != 42) + o8.ToString(); // GOOD (false positive) + if (track < 42) + o8.ToString(); // GOOD (false positive) + if (track <= 41) + o8.ToString(); // GOOD (false positive) + } + + public void Deref(int i) + { + int[] xs = maybe ? null : new int[2]; + if (i > 1) + xs[0] = 5; // BAD (maybe) + + if (i > 2) + maybe = xs[1] > 5; // BAD (maybe) + + if (i > 3) + { + var l = xs.Length; // BAD (maybe) + } + + if (i > 4) + foreach (var _ in xs) ; // BAD (maybe) (false negative) + + if (i > 5) + lock (xs) // BAD (maybe) + xs.ToString(); // Not reported - same basic block + + if (i > 6) + { + Debug.Assert(xs != null); + xs[0] = xs[1]; // GOOD + } + } + + public void F(bool b) + { + var x = b ? null : "abc"; + x = x == null ? "" : x; + if (x == null) + x.ToString(); // BAD (always) (false negative) + else + x.ToString(); // GOOD + } + + public void LengthGuard(int[] a, int[] b) + { + int alen = a == null ? 0 : a.Length; // GOOD + int blen = b == null ? 0 : b.Length; // GOOD + var sum = 0; + if (alen == blen) + { + for (int i = 0; i < alen; i++) + { + sum += a[i]; // GOOD + sum += b[i]; // GOOD + } + } + int alen2; + if (a != null) + alen2 = a.Length; // GOOD + else + alen2 = 0; + for (int i = 1; i <= alen2; ++i) + { + sum += a[i - 1]; // GOOD + } + } + + public void MissedGuard(object obj) + { + obj.ToString(); // BAD (maybe) (false negative) + var x = obj != null ? 1 : 0; + } + + private object MkMaybe() + { + if (maybe) throw new Exception(); + return new object(); + } + + public void Exceptions() + { + object obj = null; + try + { + obj = MkMaybe(); + } + catch (Exception e) + { + } + obj.ToString(); // BAD (maybe) + + object obj2 = null; + try + { + obj2 = MkMaybe(); + } + catch (Exception e) + { + Debug.Assert(false); + } + obj2.ToString(); // GOOD + + object obj3 = null; + try + { + obj3 = MkMaybe(); + } + finally { } + obj3.ToString(); // GOOD + } + + public void ClearNotNull() + { + var o = new Object(); + if (o == null) + o.ToString(); // BAD (always) (false negative) + o.ToString(); // GOOD + + try + { + MkMaybe(); + } + catch (Exception e) + { + if (e == null) + e.ToString(); // BAD (always) (false negative) + e.ToString(); // GOOD + } + + object n = null; + var o2 = n == null ? new Object() : n; + o2.ToString(); // GOOD + + var o3 = "abc"; + if (o3 == null) + o3.ToString(); // BAD (always) (false negative) + o3.ToString(); // GOOD + + var o4 = "" + null; + if (o4 == null) + o4.ToString(); // BAD (always) (false negative) + o4.ToString(); // GOOD + } + + public void CorrelatedConditions(bool cond, int num) + { + object o = null; + if (cond) + o = new Object(); + if (cond) + o.ToString(); // GOOD + + o = null; + if (flag) + o = ""; + if (flag) + o.ToString(); // GOOD + + o = null; + var other = maybe ? null : ""; + if (other == null) + o = ""; + if (other != null) + o.ToString(); // BAD (always) (reported as maybe) + else + o.ToString(); // GOOD (false positive) + + var o2 = (num < 0) ? null : ""; + if (num < 0) + o2 = ""; + else + o2.ToString(); // GOOD (false positive) + } + + public void TrackingVariable(int[] a) + { + object o = null; + object other = null; + if (maybe) + { + o = "abc"; + other = "def"; + } + + if (other is string) + o.ToString(); // GOOD (false positive) + + o = null; + int count = 0; + var found = false; + for (var i = 0; i < a.Length; i++) + { + if (a[i] == 42) + { + o = ((int)a[i]).ToString(); + count++; + if (2 > i) { } + found = true; + } + if (a[i] > 10000) + { + o = null; + count = 0; + if (2 > i) { } + found = false; + } + } + + if (count > 3) + o.ToString(); // GOOD (false positive) + + if (found) + o.ToString(); // GOOD (false positive) + + object prev = null; + for (var i = 0; i < a.Length; ++i) + { + if (i != 0) + prev.ToString(); // GOOD (false positive) + prev = a[i]; + } + + string s = null; + { + var s_null = true; + foreach (var i in a) + { + s_null = false; + s = "" + a; + } + if (!s_null) + s.ToString(); // GOOD (false positive) + } + + object r = null; + var stat = MyStatus.INIT; + while (stat == MyStatus.INIT && stat != MyStatus.READY) + { + r = MkMaybe(); + if (stat == MyStatus.INIT) + stat = MyStatus.READY; + } + r.ToString(); // GOOD (false positive) + } + + public enum MyStatus + { + READY, + INIT + } + + public void G(object obj) + { + string msg = null; + if (obj == null) + msg = "foo"; + else if (obj.GetHashCode() > 7) // GOOD + msg = "bar"; + + if (msg != null) + { + msg += "foobar"; + throw new Exception(msg); + } + obj.ToString(); // GOOD + } + + public void LoopCorr(int iters) + { + int[] a = null; + if (iters > 0) + a = new int[iters]; + + for (var i = 0; i < iters; ++i) + a[i] = 0; // GOOD (false positive) + + if (iters > 0) + { + string last = null; + for (var i = 0; i < iters; i++) + last = "abc"; + last.ToString(); // GOOD (false positive) + } + + int[] b = maybe ? null : new int[iters]; + if (iters > 0 && (b == null || b.Length < iters)) + throw new Exception(); + + for (var i = 0; i < iters; ++i) + { + b[i] = 0; // GOOD (false positive) + } + } + + void Test(Exception e, bool b) + { + Exception ioe = null; + if (b) + ioe = new Exception(""); + + if (ioe != null) + ioe = e; + else + ioe.ToString(); // BAD (always) + } + + public void LengthGuard2(int[] a, int[] b) + { + int alen = a == null ? 0 : a.Length; // GOOD + int sum = 0; + int i; + for (i = 0; i < alen; i++) + { + sum += a[i]; // GOOD + } + int blen = b == null ? 0 : b.Length; // GOOD + for (i = 0; i < blen; i++) + { + sum += b[i]; // GOOD + } + i = -3; + } + + public void CorrConds2(object x, object y) + { + if ((x != null && y == null) || (x == null && y != null)) + return; + if (x != null) + y.ToString(); // GOOD + if (y != null) + x.ToString(); // GOOD + } +} diff --git a/csharp/ql/test/query-tests/Nullness/E.cs b/csharp/ql/test/query-tests/Nullness/E.cs new file mode 100644 index 00000000000..9c2a1560ad9 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/E.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public class E +{ + public void Ex1(long[][][] a1, int ix, int len) + { + long[][] a2 = null; + var haveA2 = ix < len && (a2 = a1[ix]) != null; + long[] a3 = null; + var haveA3 = haveA2 && (a3 = a2[ix]) != null; // GOOD (false positive) + if (haveA3) + a3[0] = 0; // GOOD (false positive) + } + + public void Ex2(bool x, bool y) + { + var s1 = x ? null : ""; + var s2 = (s1 == null) ? null : ""; + if (s2 == null) + { + s1 = y ? null : ""; + s2 = (s1 == null) ? null : ""; + } + if (s2 != null) + s1.ToString(); // GOOD (false positive) + } + + public void Ex3(IEnumerable ss) + { + string last = null; + foreach (var s in new string[] { "aa", "bb" }) + last = s; + last.ToString(); // GOOD (false positive) + + last = null; + if (ss.Any()) + { + foreach (var s in ss) + last = s; + + last.ToString(); // GOOD (false positive) + } + } + + public void Ex4(IEnumerable list, int step) + { + int index = 0; + var result = new List>(); + List slice = null; + var iter = list.GetEnumerator(); + while (iter.MoveNext()) + { + var str = iter.Current; + if (index % step == 0) + { + slice = new List(); + result.Add(slice); + } + slice.Add(str); // GOOD (false positive) + ++index; + } + } + + public void Ex5(bool hasArr, int[] arr) + { + int arrLen = 0; + if (hasArr) + arrLen = arr == null ? 0 : arr.Length; + + if (arrLen > 0) + arr[0] = 0; // GOOD + } + + public const int MY_CONST_A = 1; + public const int MY_CONST_B = 2; + public const int MY_CONST_C = 3; + + public void Ex6(int[] vals, bool b1, bool b2) + { + int switchguard; + if (vals != null && b1) + switchguard = MY_CONST_A; + else if (vals != null && b2) + switchguard = MY_CONST_B; + else + switchguard = MY_CONST_C; + + switch (switchguard) + { + case MY_CONST_A: + vals[0] = 0; // GOOD + break; + case MY_CONST_C: + break; + case MY_CONST_B: + vals[0] = 0; // GOOD + break; + default: + throw new Exception(); + } + } + + public void Ex7(int[] arr1) + { + int[] arr2 = null; + if (arr1.Length > 0) + arr2 = new int[arr1.Length]; + + for (var i = 0; i < arr1.Length; i++) + arr2[i] = arr1[i]; // GOOD (false positive) + } + + public void Ex8(int x, int lim) + { + bool stop = x < 1; + int i = 0; + var obj = new object(); + while (!stop) + { + int j = 0; + while (!stop && j < lim) + { + int step = (j * obj.GetHashCode()) % 10; // GOOD (false positive) + if (step == 0) + { + obj.ToString(); // GOOD + i += 1; + stop = i >= x; + if (!stop) + { + obj = new object(); + } + else + { + obj = null; + } + continue; + } + j += step; + } + } + } + + public void Ex9(bool cond, object obj1) + { + if (cond) + { + return; + } + object obj2 = obj1; + if (obj2 != null && obj2.GetHashCode() % 5 > 2) + { + obj2.ToString(); // GOOD + cond = true; + } + if (cond) + obj2.ToString(); // GOOD + } + + public void Ex10(int[] a) + { + int n = a == null ? 0 : a.Length; + for (var i = 0; i < n; i++) + { + int x = a[i]; // GOOD + if (x > 7) + a = new int[n]; + } + } + + public void Ex11(object obj, bool b1) + { + bool b2 = obj == null ? false : b1; + if (b2 == null) + { + obj.ToString(); // GOOD + } + if (obj == null) + { + b1 = true; + } + if (b1 == null) + { + obj.ToString(); // GOOD + } + } + + public void Ex12(object o) + { + var i = o.GetHashCode(); // BAD (maybe) (false negative) + var s = o?.ToString(); + } + + public void Ex13(bool b) + { + var o = b ? null : ""; + o.M1(); // GOOD + if (b) + o.M2(); // BAD (maybe) (false negative) + else + o.Select(x => x); // BAD (maybe) (false negative) + } + + public int Ex14(string s) + { + if (s is string) + return s.Length; + return s.GetHashCode(); // BAD (always) (false negative) + } + + public void Ex15(bool b) + { + var x = ""; + if (b) + x = null; + x.ToString(); // BAD (maybe) + if (b) + x.ToString(); // BAD (always) (false negative) + } + + public void Ex16(bool b) + { + var x = ""; + if (b) + x = null; + if (b) + x.ToString(); // BAD (always) + x.ToString(); // BAD (maybe) (false negative) + } + + public int Ex17(int? i) + { + return i.Value; // BAD (maybe) (false negative) + } + + public int Ex18(int? i) + { + return (int)i; // BAD (maybe) (false negative) + } + + public int Ex19(int? i) + { + if (i.HasValue) + return i.Value; // GOOD + return -1; + } + + public int Ex20(int? i) + { + if (i != null) + return i.Value; // GOOD + return -1; + } + + public int Ex21(int? i) + { + if (i == null) + i = 0; + return i.Value; // GOOD + } +} + +public static class Extensions +{ + public static void M1(this string s) { } + public static int M2(this string s) => s.Length; +} + +// semmle-extractor-options: /r:System.Linq.dll diff --git a/csharp/ql/test/query-tests/Nullness/Forwarding.cs b/csharp/ql/test/query-tests/Nullness/Forwarding.cs index 723868ab58a..ae820066489 100644 --- a/csharp/ql/test/query-tests/Nullness/Forwarding.cs +++ b/csharp/ql/test/query-tests/Nullness/Forwarding.cs @@ -8,36 +8,36 @@ class ForwardingTests if (!s.IsNullOrEmpty()) { - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD } if (s.IsNotNullOrEmpty()) { - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD } if (!s.IsNull()) { - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD } if (s.IsNotNull()) { - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD } if (IsNotNull(s)) { - Console.WriteLine(s.Length); + Console.WriteLine(s.Length); // GOOD } if (IsNotNullWrong(s)) { - Console.WriteLine(s.Length); // maybe null + Console.WriteLine(s.Length); // BAD (always) (reported as maybe) } AssertIsNotNull(s); - Console.WriteLine(s.Length); // FP; not currently handled + Console.WriteLine(s.Length); // GOOD (false positive) } bool IsNotNull(object o) diff --git a/csharp/ql/test/query-tests/Nullness/GuardedString.cs b/csharp/ql/test/query-tests/Nullness/GuardedString.cs index 610e714c894..b5b74cf19ca 100644 --- a/csharp/ql/test/query-tests/Nullness/GuardedString.cs +++ b/csharp/ql/test/query-tests/Nullness/GuardedString.cs @@ -2,9 +2,9 @@ using System; class GuardedStringTest { - void Fn() + void Fn(bool b) { - string s = null; + string s = b ? null : ""; if (!string.IsNullOrEmpty(s)) { @@ -17,23 +17,23 @@ class GuardedStringTest } if (s?.Length == 0) - Console.WriteLine(s.Length); // null guarded + Console.WriteLine(s.Length); // GOOD if (s?.Length > 0) - Console.WriteLine(s.Length); // null guarded + Console.WriteLine(s.Length); // GOOD if (s?.Length >= 0) - Console.WriteLine(s.Length); // null guarded + Console.WriteLine(s.Length); // GOOD if (s?.Length < 10) - Console.WriteLine(s.Length); // null guarded + Console.WriteLine(s.Length); // GOOD if (s?.Length <= 10) - Console.WriteLine(s.Length); // null guarded + Console.WriteLine(s.Length); // GOOD if (s?.Length != 0) - Console.WriteLine(s.Length); // not null guarded + Console.WriteLine(s.Length); // BAD (maybe) else - Console.WriteLine(s.Length); // null guarded + Console.WriteLine(s.Length); // GOOD } } diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected new file mode 100644 index 00000000000..d8c0e36fa2e --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -0,0 +1,747 @@ +| A.cs:8:15:8:32 | access to local variable synchronizedAlways | non-null | A.cs:7:37:7:40 | null | non-null | +| A.cs:8:15:8:32 | access to local variable synchronizedAlways | null | A.cs:7:37:7:40 | null | null | +| A.cs:10:13:10:30 | access to local variable synchronizedAlways | non-null | A.cs:7:37:7:40 | null | non-null | +| A.cs:10:13:10:30 | access to local variable synchronizedAlways | null | A.cs:7:37:7:40 | null | null | +| A.cs:17:9:17:17 | access to local variable arrayNull | non-null | A.cs:16:27:16:30 | null | non-null | +| A.cs:17:9:17:17 | access to local variable arrayNull | null | A.cs:16:27:16:30 | null | null | +| A.cs:21:9:21:15 | access to local variable arrayOk | non-null | A.cs:20:19:20:29 | array creation of type Int32[] | non-null | +| A.cs:21:9:21:15 | access to local variable arrayOk | null | A.cs:20:19:20:29 | array creation of type Int32[] | null | +| A.cs:31:27:31:37 | access to local variable arrayAccess | non-null | A.cs:26:29:26:32 | null | non-null | +| A.cs:31:27:31:37 | access to local variable arrayAccess | null | A.cs:26:29:26:32 | null | null | +| A.cs:32:27:32:37 | access to local variable fieldAccess | non-null | A.cs:27:32:27:35 | null | non-null | +| A.cs:32:27:32:37 | access to local variable fieldAccess | null | A.cs:27:32:27:35 | null | null | +| A.cs:33:28:33:39 | access to local variable methodAccess | non-null | A.cs:28:31:28:34 | null | non-null | +| A.cs:33:28:33:39 | access to local variable methodAccess | null | A.cs:28:31:28:34 | null | null | +| A.cs:34:27:34:36 | access to local variable methodCall | non-null | A.cs:29:29:29:32 | null | non-null | +| A.cs:34:27:34:36 | access to local variable methodCall | null | A.cs:29:29:29:32 | null | null | +| A.cs:36:27:36:37 | access to local variable arrayAccess | non-null | A.cs:26:29:26:32 | null | non-null | +| A.cs:36:27:36:37 | access to local variable arrayAccess | null | A.cs:26:29:26:32 | null | null | +| A.cs:37:27:37:37 | access to local variable fieldAccess | non-null | A.cs:27:32:27:35 | null | non-null | +| A.cs:37:27:37:37 | access to local variable fieldAccess | null | A.cs:27:32:27:35 | null | null | +| A.cs:38:15:38:26 | access to local variable methodAccess | non-null | A.cs:28:31:28:34 | null | non-null | +| A.cs:38:15:38:26 | access to local variable methodAccess | null | A.cs:28:31:28:34 | null | null | +| A.cs:39:27:39:36 | access to local variable methodCall | non-null | A.cs:29:29:29:32 | null | non-null | +| A.cs:39:27:39:36 | access to local variable methodCall | null | A.cs:29:29:29:32 | null | null | +| A.cs:49:25:49:30 | access to local variable varRef | non-null | A.cs:48:25:48:28 | null | non-null | +| A.cs:49:25:49:30 | access to local variable varRef | null | A.cs:48:25:48:28 | null | null | +| A.cs:50:9:50:14 | access to local variable varRef | non-null | A.cs:48:25:48:28 | null | non-null | +| A.cs:50:9:50:14 | access to local variable varRef | null | A.cs:48:25:48:28 | null | null | +| A.cs:53:25:53:30 | access to local variable varRef | non-null | A.cs:52:18:52:21 | null | non-null | +| A.cs:53:25:53:30 | access to local variable varRef | null | A.cs:52:18:52:21 | null | null | +| A.cs:63:9:63:11 | access to local variable fun | non-null | A.cs:61:26:61:45 | (...) => ... | non-null | +| A.cs:63:9:63:11 | access to local variable fun | null | A.cs:61:26:61:45 | (...) => ... | null | +| Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | +| Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | +| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null | +| Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null | +| Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | +| Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | +| Assert.cs:14:23:14:23 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | +| Assert.cs:14:23:14:23 | access to local variable s | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | +| Assert.cs:15:27:15:27 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | +| Assert.cs:15:27:15:27 | access to local variable s | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | +| Assert.cs:18:26:18:26 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | +| Assert.cs:18:26:18:26 | access to local variable s | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | +| Assert.cs:19:27:19:27 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | +| Assert.cs:19:27:19:27 | access to local variable s | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | +| Assert.cs:22:23:22:23 | access to local variable s | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | +| Assert.cs:22:23:22:23 | access to local variable s | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | +| Assert.cs:22:23:22:31 | ... == ... | false | Assert.cs:22:23:22:23 | access to local variable s | non-null | +| Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:22:23:22:23 | access to local variable s | null | +| Assert.cs:23:27:23:27 | access to local variable s | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | +| Assert.cs:23:27:23:27 | access to local variable s | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | +| Assert.cs:26:23:26:23 | access to local variable s | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | +| Assert.cs:26:23:26:23 | access to local variable s | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | +| Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:26:23:26:23 | access to local variable s | null | +| Assert.cs:26:23:26:31 | ... != ... | true | Assert.cs:26:23:26:23 | access to local variable s | non-null | +| Assert.cs:27:27:27:27 | access to local variable s | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | +| Assert.cs:27:27:27:27 | access to local variable s | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | +| Assert.cs:30:24:30:24 | access to local variable s | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | +| Assert.cs:30:24:30:24 | access to local variable s | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | +| Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:30:24:30:24 | access to local variable s | null | +| Assert.cs:30:24:30:32 | ... != ... | true | Assert.cs:30:24:30:24 | access to local variable s | non-null | +| Assert.cs:31:27:31:27 | access to local variable s | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | +| Assert.cs:31:27:31:27 | access to local variable s | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | +| Assert.cs:34:24:34:24 | access to local variable s | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | +| Assert.cs:34:24:34:24 | access to local variable s | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | +| Assert.cs:34:24:34:32 | ... == ... | false | Assert.cs:34:24:34:24 | access to local variable s | non-null | +| Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:34:24:34:24 | access to local variable s | null | +| Assert.cs:35:27:35:27 | access to local variable s | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | +| Assert.cs:35:27:35:27 | access to local variable s | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | +| Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | +| Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | +| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null | +| Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null | +| Assert.cs:38:23:38:36 | ... && ... | true | Assert.cs:38:23:38:31 | ... != ... | true | +| Assert.cs:38:23:38:36 | ... && ... | true | Assert.cs:38:36:38:36 | access to parameter b | true | +| Assert.cs:39:27:39:27 | access to local variable s | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | +| Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | +| Assert.cs:42:24:42:24 | access to local variable s | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | +| Assert.cs:42:24:42:24 | access to local variable s | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | +| Assert.cs:42:24:42:32 | ... == ... | false | Assert.cs:42:24:42:24 | access to local variable s | non-null | +| Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:42:24:42:24 | access to local variable s | null | +| Assert.cs:42:24:42:37 | ... \|\| ... | false | Assert.cs:42:24:42:32 | ... == ... | false | +| Assert.cs:42:24:42:37 | ... \|\| ... | false | Assert.cs:42:37:42:37 | access to parameter b | false | +| Assert.cs:43:27:43:27 | access to local variable s | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | +| Assert.cs:43:27:43:27 | access to local variable s | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | +| Assert.cs:46:23:46:23 | access to local variable s | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | +| Assert.cs:46:23:46:23 | access to local variable s | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | +| Assert.cs:46:23:46:31 | ... == ... | false | Assert.cs:46:23:46:23 | access to local variable s | non-null | +| Assert.cs:46:23:46:31 | ... == ... | true | Assert.cs:46:23:46:23 | access to local variable s | null | +| Assert.cs:46:23:46:36 | ... && ... | true | Assert.cs:46:23:46:31 | ... == ... | true | +| Assert.cs:46:23:46:36 | ... && ... | true | Assert.cs:46:36:46:36 | access to parameter b | true | +| Assert.cs:47:27:47:27 | access to local variable s | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | +| Assert.cs:47:27:47:27 | access to local variable s | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | +| Assert.cs:50:24:50:24 | access to local variable s | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | +| Assert.cs:50:24:50:24 | access to local variable s | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | +| Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:24:50:24 | access to local variable s | null | +| Assert.cs:50:24:50:32 | ... != ... | true | Assert.cs:50:24:50:24 | access to local variable s | non-null | +| Assert.cs:50:24:50:37 | ... \|\| ... | false | Assert.cs:50:24:50:32 | ... != ... | false | +| Assert.cs:50:24:50:37 | ... \|\| ... | false | Assert.cs:50:37:50:37 | access to parameter b | false | +| Assert.cs:51:27:51:27 | access to local variable s | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | +| Assert.cs:51:27:51:27 | access to local variable s | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | +| B.cs:12:13:12:24 | access to local variable eqCallAlways | non-null | B.cs:7:26:7:29 | null | non-null | +| B.cs:12:13:12:24 | access to local variable eqCallAlways | null | B.cs:7:26:7:29 | null | null | +| B.cs:12:13:12:32 | call to operator == | false | B.cs:12:13:12:24 | access to local variable eqCallAlways | non-null | +| B.cs:12:13:12:32 | call to operator == | true | B.cs:12:13:12:24 | access to local variable eqCallAlways | null | +| B.cs:13:13:13:24 | access to local variable eqCallAlways | non-null | B.cs:7:26:7:29 | null | non-null | +| B.cs:13:13:13:24 | access to local variable eqCallAlways | null | B.cs:7:26:7:29 | null | null | +| B.cs:15:13:15:14 | access to local variable b2 | non-null | B.cs:8:16:8:19 | null | non-null | +| B.cs:15:13:15:14 | access to local variable b2 | null | B.cs:8:16:8:19 | null | null | +| B.cs:15:13:15:22 | call to operator != | false | B.cs:15:13:15:14 | access to local variable b2 | null | +| B.cs:15:13:15:22 | call to operator != | true | B.cs:15:13:15:14 | access to local variable b2 | non-null | +| B.cs:16:13:16:14 | access to local variable b2 | non-null | B.cs:8:16:8:19 | null | non-null | +| B.cs:16:13:16:14 | access to local variable b2 | null | B.cs:8:16:8:19 | null | null | +| B.cs:18:13:18:14 | access to local variable b3 | non-null | B.cs:9:16:9:19 | null | non-null | +| B.cs:18:13:18:14 | access to local variable b3 | null | B.cs:9:16:9:19 | null | null | +| B.cs:18:13:18:22 | call to operator == | false | B.cs:18:13:18:14 | access to local variable b3 | non-null | +| B.cs:18:13:18:22 | call to operator == | true | B.cs:18:13:18:14 | access to local variable b3 | null | +| B.cs:20:13:20:14 | access to local variable b3 | non-null | B.cs:9:16:9:19 | null | non-null | +| B.cs:20:13:20:14 | access to local variable b3 | null | B.cs:9:16:9:19 | null | null | +| B.cs:22:13:22:25 | access to local variable neqCallAlways | non-null | B.cs:10:27:10:30 | null | non-null | +| B.cs:22:13:22:25 | access to local variable neqCallAlways | null | B.cs:10:27:10:30 | null | null | +| B.cs:22:13:22:33 | call to operator != | false | B.cs:22:13:22:25 | access to local variable neqCallAlways | null | +| B.cs:22:13:22:33 | call to operator != | true | B.cs:22:13:22:25 | access to local variable neqCallAlways | non-null | +| B.cs:24:13:24:25 | access to local variable neqCallAlways | non-null | B.cs:10:27:10:30 | null | non-null | +| B.cs:24:13:24:25 | access to local variable neqCallAlways | null | B.cs:10:27:10:30 | null | null | +| B.cs:34:16:34:26 | !... | false | B.cs:34:18:34:25 | call to operator == | true | +| B.cs:34:16:34:26 | !... | true | B.cs:34:18:34:25 | call to operator == | false | +| B.cs:53:17:53:33 | ... != ... | false | B.cs:53:17:53:25 | (...) ... | null | +| B.cs:53:17:53:33 | ... != ... | true | B.cs:53:17:53:25 | (...) ... | non-null | +| B.cs:53:25:53:25 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | +| B.cs:53:25:53:25 | access to local variable o | null | B.cs:52:24:52:27 | null | null | +| B.cs:55:26:55:26 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | +| B.cs:55:26:55:26 | access to local variable o | null | B.cs:52:24:52:27 | null | null | +| B.cs:55:35:55:35 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | +| B.cs:55:35:55:35 | access to local variable o | null | B.cs:52:24:52:27 | null | null | +| C.cs:11:13:11:30 | !... | false | C.cs:11:15:11:29 | !... | true | +| C.cs:11:13:11:30 | !... | true | C.cs:11:15:11:29 | !... | false | +| C.cs:11:15:11:29 | !... | false | C.cs:11:17:11:28 | !... | true | +| C.cs:11:15:11:29 | !... | true | C.cs:11:17:11:28 | !... | false | +| C.cs:11:17:11:28 | !... | false | C.cs:11:19:11:27 | ... == ... | true | +| C.cs:11:17:11:28 | !... | true | C.cs:11:19:11:27 | ... == ... | false | +| C.cs:11:19:11:19 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | +| C.cs:11:19:11:19 | access to local variable o | null | C.cs:10:20:10:23 | null | null | +| C.cs:11:19:11:27 | ... == ... | false | C.cs:11:19:11:19 | access to local variable o | non-null | +| C.cs:11:19:11:27 | ... == ... | true | C.cs:11:19:11:19 | access to local variable o | null | +| C.cs:13:13:13:13 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | +| C.cs:13:13:13:13 | access to local variable o | null | C.cs:10:20:10:23 | null | null | +| C.cs:16:13:16:24 | !... | false | C.cs:16:15:16:23 | ... != ... | true | +| C.cs:16:13:16:24 | !... | true | C.cs:16:15:16:23 | ... != ... | false | +| C.cs:16:15:16:15 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | +| C.cs:16:15:16:15 | access to local variable o | null | C.cs:10:20:10:23 | null | null | +| C.cs:16:15:16:23 | ... != ... | false | C.cs:16:15:16:15 | access to local variable o | null | +| C.cs:16:15:16:23 | ... != ... | true | C.cs:16:15:16:15 | access to local variable o | non-null | +| C.cs:18:13:18:13 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | +| C.cs:18:13:18:13 | access to local variable o | null | C.cs:10:20:10:23 | null | null | +| C.cs:24:13:24:21 | ... != ... | false | C.cs:24:13:24:13 | access to parameter o | null | +| C.cs:24:13:24:21 | ... != ... | true | C.cs:24:13:24:13 | access to parameter o | non-null | +| C.cs:28:37:28:45 | ... == ... | false | C.cs:28:37:28:37 | access to parameter o | non-null | +| C.cs:28:37:28:45 | ... == ... | true | C.cs:28:37:28:37 | access to parameter o | null | +| C.cs:30:40:30:48 | ... != ... | false | C.cs:30:40:30:40 | access to parameter o | null | +| C.cs:30:40:30:48 | ... != ... | true | C.cs:30:40:30:40 | access to parameter o | non-null | +| C.cs:34:13:34:21 | ... == ... | false | C.cs:34:13:34:13 | access to parameter o | non-null | +| C.cs:34:13:34:21 | ... == ... | true | C.cs:34:13:34:13 | access to parameter o | null | +| C.cs:41:22:41:22 | access to local variable s | non-null | C.cs:40:17:40:35 | ... ? ... : ... | non-null | +| C.cs:41:22:41:22 | access to local variable s | null | C.cs:40:17:40:35 | ... ? ... : ... | null | +| C.cs:41:22:41:30 | ... == ... | false | C.cs:41:22:41:22 | access to local variable s | non-null | +| C.cs:41:22:41:30 | ... == ... | true | C.cs:41:22:41:22 | access to local variable s | null | +| C.cs:42:9:42:9 | access to local variable s | non-null | C.cs:40:17:40:35 | ... ? ... : ... | non-null | +| C.cs:42:9:42:9 | access to local variable s | null | C.cs:40:17:40:35 | ... ? ... : ... | null | +| C.cs:45:22:45:22 | access to local variable s | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | +| C.cs:45:22:45:22 | access to local variable s | null | C.cs:44:13:44:31 | ... ? ... : ... | null | +| C.cs:45:22:45:30 | ... != ... | false | C.cs:45:22:45:22 | access to local variable s | null | +| C.cs:45:22:45:30 | ... != ... | true | C.cs:45:22:45:22 | access to local variable s | non-null | +| C.cs:46:9:46:9 | access to local variable s | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | +| C.cs:46:9:46:9 | access to local variable s | null | C.cs:44:13:44:31 | ... ? ... : ... | null | +| C.cs:52:20:52:21 | access to local variable o1 | non-null | C.cs:51:18:51:29 | object creation of type Object | non-null | +| C.cs:52:20:52:21 | access to local variable o1 | null | C.cs:51:18:51:29 | object creation of type Object | null | +| C.cs:53:9:53:10 | access to local variable o1 | non-null | C.cs:51:18:51:29 | object creation of type Object | non-null | +| C.cs:53:9:53:10 | access to local variable o1 | null | C.cs:51:18:51:29 | object creation of type Object | null | +| C.cs:56:23:56:24 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | +| C.cs:56:23:56:24 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | +| C.cs:57:9:57:10 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | +| C.cs:57:9:57:10 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | +| C.cs:63:23:63:24 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | +| C.cs:63:23:63:24 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | +| C.cs:64:9:64:10 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | +| C.cs:64:9:64:10 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | +| C.cs:67:23:67:24 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | +| C.cs:67:23:67:24 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | +| C.cs:68:9:68:10 | access to local variable o2 | non-null | C.cs:66:18:66:46 | ... ? ... : ... | non-null | +| C.cs:68:9:68:10 | access to local variable o2 | null | C.cs:66:18:66:46 | ... ? ... : ... | null | +| C.cs:71:26:71:27 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | +| C.cs:71:26:71:27 | access to local variable o3 | null | C.cs:70:18:70:46 | ... ? ... : ... | null | +| C.cs:72:9:72:10 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | +| C.cs:72:9:72:10 | access to local variable o3 | null | C.cs:70:18:70:46 | ... ? ... : ... | null | +| C.cs:78:13:78:24 | call to method IsNotNull | false | C.cs:78:23:78:23 | access to local variable o | null | +| C.cs:78:13:78:24 | call to method IsNotNull | true | C.cs:78:23:78:23 | access to local variable o | non-null | +| C.cs:78:23:78:23 | access to local variable o | non-null | C.cs:77:20:77:23 | null | non-null | +| C.cs:78:23:78:23 | access to local variable o | null | C.cs:77:20:77:23 | null | null | +| C.cs:79:13:79:13 | access to local variable o | non-null | C.cs:77:20:77:23 | null | non-null | +| C.cs:79:13:79:13 | access to local variable o | null | C.cs:77:20:77:23 | null | null | +| C.cs:82:13:82:22 | !... | false | C.cs:82:14:82:22 | call to method IsNull | true | +| C.cs:82:13:82:22 | !... | true | C.cs:82:14:82:22 | call to method IsNull | false | +| C.cs:82:14:82:22 | call to method IsNull | false | C.cs:82:21:82:21 | access to local variable o | non-null | +| C.cs:82:14:82:22 | call to method IsNull | true | C.cs:82:21:82:21 | access to local variable o | null | +| C.cs:82:21:82:21 | access to local variable o | non-null | C.cs:77:20:77:23 | null | non-null | +| C.cs:82:21:82:21 | access to local variable o | null | C.cs:77:20:77:23 | null | null | +| C.cs:83:13:83:13 | access to local variable o | non-null | C.cs:77:20:77:23 | null | non-null | +| C.cs:83:13:83:13 | access to local variable o | null | C.cs:77:20:77:23 | null | null | +| C.cs:89:13:89:13 | access to local variable o | non-null | C.cs:88:20:88:23 | null | non-null | +| C.cs:89:13:89:13 | access to local variable o | null | C.cs:88:20:88:23 | null | null | +| C.cs:89:13:89:23 | ... is ... | true | C.cs:89:13:89:13 | access to local variable o | non-null | +| C.cs:90:13:90:13 | access to local variable o | non-null | C.cs:88:20:88:23 | null | non-null | +| C.cs:90:13:90:13 | access to local variable o | null | C.cs:88:20:88:23 | null | null | +| C.cs:96:15:96:15 | access to local variable o | non-null | C.cs:95:17:95:45 | ... ? ... : ... | non-null | +| C.cs:96:15:96:15 | access to local variable o | null | C.cs:95:17:95:45 | ... ? ... : ... | null | +| C.cs:97:13:97:13 | access to local variable o | non-null | C.cs:95:17:95:45 | ... ? ... : ... | non-null | +| C.cs:97:13:97:13 | access to local variable o | null | C.cs:95:17:95:45 | ... ? ... : ... | null | +| C.cs:114:22:114:28 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | +| C.cs:114:22:114:28 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | +| C.cs:114:22:114:36 | ... == ... | false | C.cs:114:22:114:28 | access to local variable colours | non-null | +| C.cs:114:22:114:36 | ... == ... | true | C.cs:114:22:114:28 | access to local variable colours | null | +| C.cs:114:22:114:59 | ... \|\| ... | false | C.cs:114:22:114:36 | ... == ... | false | +| C.cs:114:22:114:59 | ... \|\| ... | false | C.cs:114:41:114:59 | ... == ... | false | +| C.cs:114:41:114:47 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | +| C.cs:114:41:114:47 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | +| C.cs:114:73:114:79 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | +| C.cs:114:73:114:79 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | +| C.cs:121:13:121:20 | access to local variable children | non-null | C.cs:119:29:119:32 | null | non-null | +| C.cs:121:13:121:20 | access to local variable children | null | C.cs:119:29:119:32 | null | null | +| C.cs:121:13:121:28 | ... == ... | false | C.cs:121:13:121:20 | access to local variable children | non-null | +| C.cs:121:13:121:28 | ... == ... | true | C.cs:121:13:121:20 | access to local variable children | null | +| C.cs:130:13:130:38 | ... == ... | false | C.cs:130:14:130:29 | ... = ... | non-null | +| C.cs:130:13:130:38 | ... == ... | true | C.cs:130:14:130:29 | ... = ... | null | +| C.cs:130:13:130:55 | ... \|\| ... | false | C.cs:130:13:130:38 | ... == ... | false | +| C.cs:130:13:130:55 | ... \|\| ... | false | C.cs:130:43:130:55 | ... > ... | false | +| C.cs:130:43:130:44 | access to local variable ok | non-null | C.cs:130:20:130:28 | ... = ... | non-null | +| C.cs:130:43:130:44 | access to local variable ok | null | C.cs:130:20:130:28 | ... = ... | null | +| C.cs:138:13:138:48 | ... \|\| ... | false | C.cs:138:13:138:30 | call to local function Foo | false | +| C.cs:138:13:138:48 | ... \|\| ... | false | C.cs:138:35:138:48 | ... > ... | false | +| C.cs:138:35:138:37 | access to local variable ok2 | non-null | C.cs:138:23:138:29 | "hello" | non-null | +| C.cs:138:35:138:37 | access to local variable ok2 | null | C.cs:138:23:138:29 | "hello" | null | +| C.cs:146:13:146:39 | ... != ... | false | C.cs:146:14:146:30 | ... = ... | null | +| C.cs:146:13:146:39 | ... != ... | true | C.cs:146:14:146:30 | ... = ... | non-null | +| C.cs:146:13:146:57 | ... && ... | true | C.cs:146:13:146:39 | ... != ... | true | +| C.cs:146:13:146:57 | ... && ... | true | C.cs:146:44:146:57 | ... > ... | true | +| C.cs:146:44:146:46 | access to local variable ok3 | non-null | C.cs:146:26:146:29 | null | non-null | +| C.cs:146:44:146:46 | access to local variable ok3 | null | C.cs:146:26:146:29 | null | null | +| C.cs:158:16:158:16 | access to local variable s | non-null | C.cs:156:17:156:20 | null | non-null | +| C.cs:158:16:158:16 | access to local variable s | null | C.cs:156:17:156:20 | null | null | +| C.cs:158:16:158:24 | ... != ... | false | C.cs:158:16:158:16 | access to local variable s | null | +| C.cs:158:16:158:24 | ... != ... | true | C.cs:158:16:158:16 | access to local variable s | non-null | +| C.cs:166:16:166:16 | access to local variable s | non-null | C.cs:164:17:164:20 | null | non-null | +| C.cs:166:16:166:16 | access to local variable s | null | C.cs:164:17:164:20 | null | null | +| C.cs:166:16:166:24 | ... != ... | false | C.cs:166:16:166:16 | access to local variable s | null | +| C.cs:166:16:166:24 | ... != ... | true | C.cs:166:16:166:16 | access to local variable s | non-null | +| C.cs:171:13:171:13 | access to local variable s | non-null | C.cs:168:13:168:16 | null | non-null | +| C.cs:171:13:171:13 | access to local variable s | null | C.cs:168:13:168:16 | null | null | +| C.cs:173:16:173:16 | access to local variable s | non-null | C.cs:168:13:168:16 | null | non-null | +| C.cs:173:16:173:16 | access to local variable s | null | C.cs:168:13:168:16 | null | null | +| C.cs:173:16:173:24 | ... != ... | false | C.cs:173:16:173:16 | access to local variable s | null | +| C.cs:173:16:173:24 | ... != ... | true | C.cs:173:16:173:16 | access to local variable s | non-null | +| C.cs:187:16:187:24 | ... != ... | false | C.cs:187:16:187:16 | access to local variable s | null | +| C.cs:187:16:187:24 | ... != ... | true | C.cs:187:16:187:16 | access to local variable s | non-null | +| C.cs:212:13:212:13 | access to local variable s | non-null | C.cs:211:17:211:35 | ... ? ... : ... | non-null | +| C.cs:212:13:212:13 | access to local variable s | null | C.cs:211:17:211:35 | ... ? ... : ... | null | +| C.cs:212:13:212:21 | ... != ... | false | C.cs:212:13:212:13 | access to local variable s | null | +| C.cs:212:13:212:21 | ... != ... | true | C.cs:212:13:212:13 | access to local variable s | non-null | +| C.cs:214:13:214:13 | access to local variable s | non-null | C.cs:211:17:211:35 | ... ? ... : ... | non-null | +| C.cs:214:13:214:13 | access to local variable s | null | C.cs:211:17:211:35 | ... ? ... : ... | null | +| C.cs:218:13:218:21 | ... == ... | false | C.cs:218:13:218:13 | access to local variable s | non-null | +| C.cs:218:13:218:21 | ... == ... | true | C.cs:218:13:218:13 | access to local variable s | null | +| C.cs:222:13:222:13 | access to local variable s | non-null | C.cs:221:13:221:14 | "" | non-null | +| C.cs:222:13:222:13 | access to local variable s | null | C.cs:221:13:221:14 | "" | null | +| C.cs:222:13:222:21 | ... != ... | false | C.cs:222:13:222:13 | access to local variable s | null | +| C.cs:222:13:222:21 | ... != ... | true | C.cs:222:13:222:13 | access to local variable s | non-null | +| C.cs:222:13:222:42 | ... && ... | true | C.cs:222:13:222:21 | ... != ... | true | +| C.cs:222:13:222:42 | ... && ... | true | C.cs:222:26:222:42 | ... == ... | true | +| C.cs:222:26:222:26 | access to local variable s | non-null | C.cs:221:13:221:14 | "" | non-null | +| C.cs:222:26:222:26 | access to local variable s | null | C.cs:221:13:221:14 | "" | null | +| C.cs:230:22:230:30 | ... != ... | false | C.cs:230:22:230:22 | access to local variable s | null | +| C.cs:230:22:230:30 | ... != ... | true | C.cs:230:22:230:22 | access to local variable s | non-null | +| C.cs:236:24:236:32 | ... == ... | false | C.cs:236:24:236:24 | access to local variable s | non-null | +| C.cs:236:24:236:32 | ... == ... | true | C.cs:236:24:236:24 | access to local variable s | null | +| C.cs:250:9:250:9 | access to local variable a | non-null | C.cs:249:19:249:22 | null | non-null | +| C.cs:250:9:250:9 | access to local variable a | null | C.cs:249:19:249:22 | null | null | +| C.cs:253:9:253:9 | access to local variable a | non-null | C.cs:252:13:252:23 | array creation of type Int32[] | non-null | +| C.cs:253:9:253:9 | access to local variable a | null | C.cs:252:13:252:23 | array creation of type Int32[] | null | +| C.cs:261:9:261:10 | access to local variable ia | non-null | C.cs:258:20:258:23 | null | non-null | +| C.cs:261:9:261:10 | access to local variable ia | null | C.cs:258:20:258:23 | null | null | +| C.cs:262:20:262:21 | access to local variable sa | non-null | C.cs:259:23:259:26 | null | non-null | +| C.cs:262:20:262:21 | access to local variable sa | null | C.cs:259:23:259:26 | null | null | +| C.cs:264:9:264:10 | access to local variable ia | non-null | C.cs:258:20:258:23 | null | non-null | +| C.cs:264:9:264:10 | access to local variable ia | null | C.cs:258:20:258:23 | null | null | +| C.cs:265:16:265:17 | access to local variable sa | non-null | C.cs:259:23:259:26 | null | non-null | +| C.cs:265:16:265:17 | access to local variable sa | null | C.cs:259:23:259:26 | null | null | +| D.cs:28:13:28:25 | ... != ... | false | D.cs:28:13:28:17 | access to parameter param | null | +| D.cs:28:13:28:25 | ... != ... | true | D.cs:28:13:28:17 | access to parameter param | non-null | +| D.cs:37:13:37:23 | ... is ... | true | D.cs:37:13:37:13 | access to parameter x | non-null | +| D.cs:38:13:38:21 | ... == ... | false | D.cs:38:13:38:13 | access to parameter x | non-null | +| D.cs:38:13:38:21 | ... == ... | true | D.cs:38:13:38:13 | access to parameter x | null | +| D.cs:39:16:39:24 | ... == ... | false | D.cs:39:16:39:16 | access to parameter x | non-null | +| D.cs:39:16:39:24 | ... == ... | true | D.cs:39:16:39:16 | access to parameter x | null | +| D.cs:45:13:45:14 | access to local variable o1 | non-null | D.cs:44:18:44:44 | ... ? ... : ... | non-null | +| D.cs:45:13:45:14 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | +| D.cs:45:13:45:22 | ... != ... | false | D.cs:45:13:45:14 | access to local variable o1 | null | +| D.cs:45:13:45:22 | ... != ... | true | D.cs:45:13:45:14 | access to local variable o1 | non-null | +| D.cs:45:25:45:26 | access to local variable o1 | non-null | D.cs:44:18:44:44 | ... ? ... : ... | non-null | +| D.cs:45:25:45:26 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | +| D.cs:48:13:48:14 | access to local variable o2 | non-null | D.cs:47:18:47:34 | ... ? ... : ... | non-null | +| D.cs:48:13:48:14 | access to local variable o2 | null | D.cs:47:18:47:34 | ... ? ... : ... | null | +| D.cs:48:13:48:24 | ... is ... | true | D.cs:48:13:48:14 | access to local variable o2 | non-null | +| D.cs:48:27:48:28 | access to local variable o2 | non-null | D.cs:47:18:47:34 | ... ? ... : ... | non-null | +| D.cs:48:27:48:28 | access to local variable o2 | null | D.cs:47:18:47:34 | ... ? ... : ... | null | +| D.cs:51:13:51:44 | ... != ... | false | D.cs:51:14:51:35 | ... = ... | null | +| D.cs:51:13:51:44 | ... != ... | true | D.cs:51:14:51:35 | ... = ... | non-null | +| D.cs:52:13:52:14 | access to local variable o3 | non-null | D.cs:51:19:51:35 | ... ? ... : ... | non-null | +| D.cs:52:13:52:14 | access to local variable o3 | null | D.cs:51:19:51:35 | ... ? ... : ... | null | +| D.cs:55:13:55:42 | ... != ... | false | D.cs:55:14:55:32 | ... && ... | false | +| D.cs:55:13:55:42 | ... != ... | true | D.cs:55:14:55:32 | ... && ... | true | +| D.cs:55:14:55:32 | ... && ... | true | D.cs:55:14:55:18 | ... > ... | true | +| D.cs:55:14:55:32 | ... && ... | true | D.cs:55:23:55:32 | ... != ... | true | +| D.cs:55:23:55:24 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | +| D.cs:55:23:55:24 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:55:23:55:32 | ... != ... | false | D.cs:55:23:55:24 | access to local variable o4 | null | +| D.cs:55:23:55:32 | ... != ... | true | D.cs:55:23:55:24 | access to local variable o4 | non-null | +| D.cs:56:13:56:14 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | +| D.cs:56:13:56:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:58:19:58:20 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | +| D.cs:58:19:58:20 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:58:19:58:28 | ... != ... | false | D.cs:58:19:58:20 | access to local variable o4 | null | +| D.cs:58:19:58:28 | ... != ... | true | D.cs:58:19:58:20 | access to local variable o4 | non-null | +| D.cs:59:13:59:14 | access to local variable o5 | non-null | D.cs:58:18:58:41 | ... ? ... : ... | non-null | +| D.cs:59:13:59:14 | access to local variable o5 | null | D.cs:58:18:58:41 | ... ? ... : ... | null | +| D.cs:59:13:59:22 | ... != ... | false | D.cs:59:13:59:14 | access to local variable o5 | null | +| D.cs:59:13:59:22 | ... != ... | true | D.cs:59:13:59:14 | access to local variable o5 | non-null | +| D.cs:60:13:60:14 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | +| D.cs:60:13:60:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:61:13:61:14 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | +| D.cs:61:13:61:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:61:13:61:22 | ... != ... | false | D.cs:61:13:61:14 | access to local variable o4 | null | +| D.cs:61:13:61:22 | ... != ... | true | D.cs:61:13:61:14 | access to local variable o4 | non-null | +| D.cs:62:13:62:14 | access to local variable o5 | non-null | D.cs:58:18:58:41 | ... ? ... : ... | non-null | +| D.cs:62:13:62:14 | access to local variable o5 | null | D.cs:58:18:58:41 | ... ? ... : ... | null | +| D.cs:65:13:65:29 | !... | false | D.cs:65:14:65:29 | call to method CustomIsNull | true | +| D.cs:65:13:65:29 | !... | true | D.cs:65:14:65:29 | call to method CustomIsNull | false | +| D.cs:65:14:65:29 | call to method CustomIsNull | false | D.cs:65:27:65:28 | access to local variable o6 | non-null | +| D.cs:65:14:65:29 | call to method CustomIsNull | true | D.cs:65:27:65:28 | access to local variable o6 | null | +| D.cs:65:27:65:28 | access to local variable o6 | non-null | D.cs:64:18:64:34 | ... ? ... : ... | non-null | +| D.cs:65:27:65:28 | access to local variable o6 | null | D.cs:64:18:64:34 | ... ? ... : ... | null | +| D.cs:66:13:66:14 | access to local variable o6 | non-null | D.cs:64:18:64:34 | ... ? ... : ... | non-null | +| D.cs:66:13:66:14 | access to local variable o6 | null | D.cs:64:18:64:34 | ... ? ... : ... | null | +| D.cs:69:18:69:19 | access to local variable o7 | non-null | D.cs:68:18:68:34 | ... ? ... : ... | non-null | +| D.cs:69:18:69:19 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | +| D.cs:69:18:69:27 | ... != ... | false | D.cs:69:18:69:19 | access to local variable o7 | null | +| D.cs:69:18:69:27 | ... != ... | true | D.cs:69:18:69:19 | access to local variable o7 | non-null | +| D.cs:69:18:69:36 | ... && ... | true | D.cs:69:18:69:27 | ... != ... | true | +| D.cs:69:18:69:36 | ... && ... | true | D.cs:69:32:69:36 | ... > ... | true | +| D.cs:70:13:70:14 | access to local variable ok | false | D.cs:69:18:69:36 | ... && ... | false | +| D.cs:70:13:70:14 | access to local variable ok | true | D.cs:69:18:69:36 | ... && ... | true | +| D.cs:71:13:71:14 | access to local variable o7 | non-null | D.cs:68:18:68:34 | ... ? ... : ... | non-null | +| D.cs:71:13:71:14 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | +| D.cs:73:13:73:14 | access to local variable o7 | non-null | D.cs:68:18:68:34 | ... ? ... : ... | non-null | +| D.cs:73:13:73:14 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | +| D.cs:76:21:76:22 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | +| D.cs:76:21:76:22 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:76:21:76:30 | ... == ... | false | D.cs:76:21:76:22 | access to local variable o8 | non-null | +| D.cs:76:21:76:30 | ... == ... | true | D.cs:76:21:76:22 | access to local variable o8 | null | +| D.cs:78:13:78:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | +| D.cs:78:13:78:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:80:13:80:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | +| D.cs:80:13:80:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:82:13:82:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | +| D.cs:82:13:82:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:84:13:84:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | +| D.cs:84:13:84:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:91:13:91:14 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:91:13:91:14 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:94:21:94:22 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:94:21:94:22 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:98:21:98:22 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:98:21:98:22 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:102:31:102:32 | access to local variable xs | empty | D.cs:89:20:89:44 | ... ? ... : ... | empty | +| D.cs:102:31:102:32 | access to local variable xs | non-empty | D.cs:89:20:89:44 | ... ? ... : ... | non-empty | +| D.cs:102:31:102:32 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:102:31:102:32 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:105:19:105:20 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:105:19:105:20 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:106:17:106:18 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:106:17:106:18 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:110:26:110:27 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:110:26:110:27 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:110:26:110:35 | ... != ... | false | D.cs:110:26:110:27 | access to local variable xs | null | +| D.cs:110:26:110:35 | ... != ... | true | D.cs:110:26:110:27 | access to local variable xs | non-null | +| D.cs:111:13:111:14 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:111:13:111:14 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:111:21:111:22 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | +| D.cs:111:21:111:22 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:118:13:118:13 | access to local variable x | non-null | D.cs:117:17:117:32 | ... ? ... : ... | non-null | +| D.cs:118:13:118:13 | access to local variable x | null | D.cs:117:17:117:32 | ... ? ... : ... | null | +| D.cs:118:13:118:21 | ... == ... | false | D.cs:118:13:118:13 | access to local variable x | non-null | +| D.cs:118:13:118:21 | ... == ... | true | D.cs:118:13:118:13 | access to local variable x | null | +| D.cs:118:30:118:30 | access to local variable x | non-null | D.cs:117:17:117:32 | ... ? ... : ... | non-null | +| D.cs:118:30:118:30 | access to local variable x | null | D.cs:117:17:117:32 | ... ? ... : ... | null | +| D.cs:119:13:119:13 | access to local variable x | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | +| D.cs:119:13:119:13 | access to local variable x | null | D.cs:118:13:118:30 | ... ? ... : ... | null | +| D.cs:119:13:119:21 | ... == ... | false | D.cs:119:13:119:13 | access to local variable x | non-null | +| D.cs:119:13:119:21 | ... == ... | true | D.cs:119:13:119:13 | access to local variable x | null | +| D.cs:120:13:120:13 | access to local variable x | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | +| D.cs:120:13:120:13 | access to local variable x | null | D.cs:118:13:118:30 | ... ? ... : ... | null | +| D.cs:122:13:122:13 | access to local variable x | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | +| D.cs:122:13:122:13 | access to local variable x | null | D.cs:118:13:118:30 | ... ? ... : ... | null | +| D.cs:127:20:127:28 | ... == ... | false | D.cs:127:20:127:20 | access to parameter a | non-null | +| D.cs:127:20:127:28 | ... == ... | true | D.cs:127:20:127:20 | access to parameter a | null | +| D.cs:128:20:128:28 | ... == ... | false | D.cs:128:20:128:20 | access to parameter b | non-null | +| D.cs:128:20:128:28 | ... == ... | true | D.cs:128:20:128:20 | access to parameter b | null | +| D.cs:139:13:139:21 | ... != ... | false | D.cs:139:13:139:13 | access to parameter a | null | +| D.cs:139:13:139:21 | ... != ... | true | D.cs:139:13:139:13 | access to parameter a | non-null | +| D.cs:152:17:152:27 | ... != ... | false | D.cs:152:17:152:19 | access to parameter obj | null | +| D.cs:152:17:152:27 | ... != ... | true | D.cs:152:17:152:19 | access to parameter obj | non-null | +| D.cs:182:9:182:12 | access to local variable obj2 | non-null | D.cs:176:20:176:28 | call to method MkMaybe | non-null | +| D.cs:182:9:182:12 | access to local variable obj2 | null | D.cs:176:20:176:28 | call to method MkMaybe | null | +| D.cs:196:13:196:13 | access to local variable o | non-null | D.cs:195:17:195:28 | object creation of type Object | non-null | +| D.cs:196:13:196:13 | access to local variable o | null | D.cs:195:17:195:28 | object creation of type Object | null | +| D.cs:196:13:196:21 | ... == ... | false | D.cs:196:13:196:13 | access to local variable o | non-null | +| D.cs:196:13:196:21 | ... == ... | true | D.cs:196:13:196:13 | access to local variable o | null | +| D.cs:197:13:197:13 | access to local variable o | non-null | D.cs:195:17:195:28 | object creation of type Object | non-null | +| D.cs:197:13:197:13 | access to local variable o | null | D.cs:195:17:195:28 | object creation of type Object | null | +| D.cs:198:9:198:9 | access to local variable o | non-null | D.cs:195:17:195:28 | object creation of type Object | non-null | +| D.cs:198:9:198:9 | access to local variable o | null | D.cs:195:17:195:28 | object creation of type Object | null | +| D.cs:206:17:206:25 | ... == ... | false | D.cs:206:17:206:17 | access to local variable e | non-null | +| D.cs:206:17:206:25 | ... == ... | true | D.cs:206:17:206:17 | access to local variable e | null | +| D.cs:212:18:212:18 | access to local variable n | non-null | D.cs:211:20:211:23 | null | non-null | +| D.cs:212:18:212:18 | access to local variable n | null | D.cs:211:20:211:23 | null | null | +| D.cs:212:18:212:26 | ... == ... | false | D.cs:212:18:212:18 | access to local variable n | non-null | +| D.cs:212:18:212:26 | ... == ... | true | D.cs:212:18:212:18 | access to local variable n | null | +| D.cs:212:45:212:45 | access to local variable n | non-null | D.cs:211:20:211:23 | null | non-null | +| D.cs:212:45:212:45 | access to local variable n | null | D.cs:211:20:211:23 | null | null | +| D.cs:213:9:213:10 | access to local variable o2 | non-null | D.cs:212:18:212:45 | ... ? ... : ... | non-null | +| D.cs:213:9:213:10 | access to local variable o2 | null | D.cs:212:18:212:45 | ... ? ... : ... | null | +| D.cs:216:13:216:14 | access to local variable o3 | non-null | D.cs:215:18:215:22 | "abc" | non-null | +| D.cs:216:13:216:14 | access to local variable o3 | null | D.cs:215:18:215:22 | "abc" | null | +| D.cs:216:13:216:22 | ... == ... | false | D.cs:216:13:216:14 | access to local variable o3 | non-null | +| D.cs:216:13:216:22 | ... == ... | true | D.cs:216:13:216:14 | access to local variable o3 | null | +| D.cs:217:13:217:14 | access to local variable o3 | non-null | D.cs:215:18:215:22 | "abc" | non-null | +| D.cs:217:13:217:14 | access to local variable o3 | null | D.cs:215:18:215:22 | "abc" | null | +| D.cs:218:9:218:10 | access to local variable o3 | non-null | D.cs:215:18:215:22 | "abc" | non-null | +| D.cs:218:9:218:10 | access to local variable o3 | null | D.cs:215:18:215:22 | "abc" | null | +| D.cs:220:18:220:26 | ... + ... | non-null | D.cs:220:23:220:26 | null | non-null | +| D.cs:220:18:220:26 | ... + ... | null | D.cs:220:23:220:26 | null | null | +| D.cs:221:13:221:14 | access to local variable o4 | non-null | D.cs:220:18:220:26 | ... + ... | non-null | +| D.cs:221:13:221:14 | access to local variable o4 | null | D.cs:220:18:220:26 | ... + ... | null | +| D.cs:221:13:221:22 | ... == ... | false | D.cs:221:13:221:14 | access to local variable o4 | non-null | +| D.cs:221:13:221:22 | ... == ... | true | D.cs:221:13:221:14 | access to local variable o4 | null | +| D.cs:222:13:222:14 | access to local variable o4 | non-null | D.cs:220:18:220:26 | ... + ... | non-null | +| D.cs:222:13:222:14 | access to local variable o4 | null | D.cs:220:18:220:26 | ... + ... | null | +| D.cs:223:9:223:10 | access to local variable o4 | non-null | D.cs:220:18:220:26 | ... + ... | non-null | +| D.cs:223:9:223:10 | access to local variable o4 | null | D.cs:220:18:220:26 | ... + ... | null | +| D.cs:242:13:242:17 | access to local variable other | non-null | D.cs:241:21:241:37 | ... ? ... : ... | non-null | +| D.cs:242:13:242:17 | access to local variable other | null | D.cs:241:21:241:37 | ... ? ... : ... | null | +| D.cs:242:13:242:25 | ... == ... | false | D.cs:242:13:242:17 | access to local variable other | non-null | +| D.cs:242:13:242:25 | ... == ... | true | D.cs:242:13:242:17 | access to local variable other | null | +| D.cs:244:13:244:17 | access to local variable other | non-null | D.cs:241:21:241:37 | ... ? ... : ... | non-null | +| D.cs:244:13:244:17 | access to local variable other | null | D.cs:241:21:241:37 | ... ? ... : ... | null | +| D.cs:244:13:244:25 | ... != ... | false | D.cs:244:13:244:17 | access to local variable other | null | +| D.cs:244:13:244:25 | ... != ... | true | D.cs:244:13:244:17 | access to local variable other | non-null | +| D.cs:253:13:253:14 | access to local variable o2 | non-null | D.cs:249:18:249:38 | ... ? ... : ... | non-null | +| D.cs:253:13:253:14 | access to local variable o2 | null | D.cs:249:18:249:38 | ... ? ... : ... | null | +| D.cs:266:13:266:27 | ... is ... | true | D.cs:266:13:266:17 | access to local variable other | non-null | +| D.cs:310:21:310:26 | ... + ... | non-null | D.cs:310:26:310:26 | access to parameter a | non-null | +| D.cs:310:21:310:26 | ... + ... | null | D.cs:310:26:310:26 | access to parameter a | null | +| D.cs:312:17:312:23 | !... | false | D.cs:312:18:312:23 | access to local variable s_null | true | +| D.cs:312:17:312:23 | !... | true | D.cs:312:18:312:23 | access to local variable s_null | false | +| D.cs:318:16:318:62 | ... && ... | true | D.cs:318:16:318:36 | ... == ... | true | +| D.cs:318:16:318:62 | ... && ... | true | D.cs:318:41:318:62 | ... != ... | true | +| D.cs:336:13:336:23 | ... == ... | false | D.cs:336:13:336:15 | access to parameter obj | non-null | +| D.cs:336:13:336:23 | ... == ... | true | D.cs:336:13:336:15 | access to parameter obj | null | +| D.cs:341:13:341:23 | ... != ... | false | D.cs:341:13:341:15 | access to local variable msg | null | +| D.cs:341:13:341:23 | ... != ... | true | D.cs:341:13:341:15 | access to local variable msg | non-null | +| D.cs:343:13:343:27 | ... + ... | non-null | D.cs:343:13:343:15 | access to local variable msg | non-null | +| D.cs:343:13:343:27 | ... + ... | null | D.cs:343:13:343:15 | access to local variable msg | null | +| D.cs:344:33:344:35 | access to local variable msg | non-null | D.cs:343:13:343:27 | ... + ... | non-null | +| D.cs:344:33:344:35 | access to local variable msg | null | D.cs:343:13:343:27 | ... + ... | null | +| D.cs:367:13:367:56 | ... && ... | true | D.cs:367:13:367:21 | ... > ... | true | +| D.cs:367:13:367:56 | ... && ... | true | D.cs:367:27:367:55 | ... \|\| ... | true | +| D.cs:367:27:367:27 | access to local variable b | non-null | D.cs:366:19:366:47 | ... ? ... : ... | non-null | +| D.cs:367:27:367:27 | access to local variable b | null | D.cs:366:19:366:47 | ... ? ... : ... | null | +| D.cs:367:27:367:35 | ... == ... | false | D.cs:367:27:367:27 | access to local variable b | non-null | +| D.cs:367:27:367:35 | ... == ... | true | D.cs:367:27:367:27 | access to local variable b | null | +| D.cs:367:27:367:55 | ... \|\| ... | false | D.cs:367:27:367:35 | ... == ... | false | +| D.cs:367:27:367:55 | ... \|\| ... | false | D.cs:367:40:367:55 | ... < ... | false | +| D.cs:367:40:367:40 | access to local variable b | non-null | D.cs:366:19:366:47 | ... ? ... : ... | non-null | +| D.cs:367:40:367:40 | access to local variable b | null | D.cs:366:19:366:47 | ... ? ... : ... | null | +| D.cs:372:13:372:13 | access to local variable b | non-null | D.cs:366:19:366:47 | ... ? ... : ... | non-null | +| D.cs:372:13:372:13 | access to local variable b | null | D.cs:366:19:366:47 | ... ? ... : ... | null | +| D.cs:382:13:382:23 | ... != ... | false | D.cs:382:13:382:15 | access to local variable ioe | null | +| D.cs:382:13:382:23 | ... != ... | true | D.cs:382:13:382:15 | access to local variable ioe | non-null | +| D.cs:390:20:390:28 | ... == ... | false | D.cs:390:20:390:20 | access to parameter a | non-null | +| D.cs:390:20:390:28 | ... == ... | true | D.cs:390:20:390:20 | access to parameter a | null | +| D.cs:397:20:397:28 | ... == ... | false | D.cs:397:20:397:20 | access to parameter b | non-null | +| D.cs:397:20:397:28 | ... == ... | true | D.cs:397:20:397:20 | access to parameter b | null | +| D.cs:407:13:407:64 | ... \|\| ... | false | D.cs:407:14:407:35 | ... && ... | false | +| D.cs:407:13:407:64 | ... \|\| ... | false | D.cs:407:42:407:63 | ... && ... | false | +| D.cs:407:14:407:22 | ... != ... | false | D.cs:407:14:407:14 | access to parameter x | null | +| D.cs:407:14:407:22 | ... != ... | true | D.cs:407:14:407:14 | access to parameter x | non-null | +| D.cs:407:14:407:35 | ... && ... | true | D.cs:407:14:407:22 | ... != ... | true | +| D.cs:407:14:407:35 | ... && ... | true | D.cs:407:27:407:35 | ... == ... | true | +| D.cs:407:27:407:35 | ... == ... | false | D.cs:407:27:407:27 | access to parameter y | non-null | +| D.cs:407:27:407:35 | ... == ... | true | D.cs:407:27:407:27 | access to parameter y | null | +| D.cs:407:42:407:50 | ... == ... | false | D.cs:407:42:407:42 | access to parameter x | non-null | +| D.cs:407:42:407:50 | ... == ... | true | D.cs:407:42:407:42 | access to parameter x | null | +| D.cs:407:42:407:63 | ... && ... | true | D.cs:407:42:407:50 | ... == ... | true | +| D.cs:407:42:407:63 | ... && ... | true | D.cs:407:55:407:63 | ... != ... | true | +| D.cs:407:55:407:63 | ... != ... | false | D.cs:407:55:407:55 | access to parameter y | null | +| D.cs:407:55:407:63 | ... != ... | true | D.cs:407:55:407:55 | access to parameter y | non-null | +| D.cs:409:13:409:21 | ... != ... | false | D.cs:409:13:409:13 | access to parameter x | null | +| D.cs:409:13:409:21 | ... != ... | true | D.cs:409:13:409:13 | access to parameter x | non-null | +| D.cs:411:13:411:21 | ... != ... | false | D.cs:411:13:411:13 | access to parameter y | null | +| D.cs:411:13:411:21 | ... != ... | true | D.cs:411:13:411:13 | access to parameter y | non-null | +| E.cs:10:22:10:54 | ... && ... | true | E.cs:10:22:10:29 | ... < ... | true | +| E.cs:10:22:10:54 | ... && ... | true | E.cs:10:34:10:54 | ... != ... | true | +| E.cs:10:34:10:54 | ... != ... | false | E.cs:10:35:10:45 | ... = ... | null | +| E.cs:10:34:10:54 | ... != ... | true | E.cs:10:35:10:45 | ... = ... | non-null | +| E.cs:12:22:12:27 | access to local variable haveA2 | false | E.cs:10:22:10:54 | ... && ... | false | +| E.cs:12:22:12:27 | access to local variable haveA2 | true | E.cs:10:22:10:54 | ... && ... | true | +| E.cs:12:22:12:52 | ... && ... | true | E.cs:12:22:12:27 | access to local variable haveA2 | true | +| E.cs:12:22:12:52 | ... && ... | true | E.cs:12:32:12:52 | ... != ... | true | +| E.cs:12:32:12:52 | ... != ... | false | E.cs:12:33:12:43 | ... = ... | null | +| E.cs:12:32:12:52 | ... != ... | true | E.cs:12:33:12:43 | ... = ... | non-null | +| E.cs:13:13:13:18 | access to local variable haveA3 | false | E.cs:12:22:12:52 | ... && ... | false | +| E.cs:13:13:13:18 | access to local variable haveA3 | true | E.cs:12:22:12:52 | ... && ... | true | +| E.cs:20:19:20:20 | access to local variable s1 | non-null | E.cs:19:18:19:30 | ... ? ... : ... | non-null | +| E.cs:20:19:20:20 | access to local variable s1 | null | E.cs:19:18:19:30 | ... ? ... : ... | null | +| E.cs:20:19:20:28 | ... == ... | false | E.cs:20:19:20:20 | access to local variable s1 | non-null | +| E.cs:20:19:20:28 | ... == ... | true | E.cs:20:19:20:20 | access to local variable s1 | null | +| E.cs:21:13:21:14 | access to local variable s2 | non-null | E.cs:20:18:20:41 | ... ? ... : ... | non-null | +| E.cs:21:13:21:14 | access to local variable s2 | null | E.cs:20:18:20:41 | ... ? ... : ... | null | +| E.cs:21:13:21:22 | ... == ... | false | E.cs:21:13:21:14 | access to local variable s2 | non-null | +| E.cs:21:13:21:22 | ... == ... | true | E.cs:21:13:21:14 | access to local variable s2 | null | +| E.cs:24:19:24:20 | access to local variable s1 | non-null | E.cs:23:18:23:30 | ... ? ... : ... | non-null | +| E.cs:24:19:24:20 | access to local variable s1 | null | E.cs:23:18:23:30 | ... ? ... : ... | null | +| E.cs:24:19:24:28 | ... == ... | false | E.cs:24:19:24:20 | access to local variable s1 | non-null | +| E.cs:24:19:24:28 | ... == ... | true | E.cs:24:19:24:20 | access to local variable s1 | null | +| E.cs:26:13:26:22 | ... != ... | false | E.cs:26:13:26:14 | access to local variable s2 | null | +| E.cs:26:13:26:22 | ... != ... | true | E.cs:26:13:26:14 | access to local variable s2 | non-null | +| E.cs:53:16:53:19 | access to local variable iter | non-null | E.cs:52:20:52:39 | call to method GetEnumerator | non-null | +| E.cs:53:16:53:19 | access to local variable iter | null | E.cs:52:20:52:39 | call to method GetEnumerator | null | +| E.cs:55:23:55:26 | access to local variable iter | non-null | E.cs:52:20:52:39 | call to method GetEnumerator | non-null | +| E.cs:55:23:55:26 | access to local variable iter | null | E.cs:52:20:52:39 | call to method GetEnumerator | null | +| E.cs:59:17:59:22 | access to local variable result | non-null | E.cs:50:22:50:45 | object creation of type List> | non-null | +| E.cs:59:17:59:22 | access to local variable result | null | E.cs:50:22:50:45 | object creation of type List> | null | +| E.cs:59:28:59:32 | access to local variable slice | non-null | E.cs:58:25:58:42 | object creation of type List | non-null | +| E.cs:59:28:59:32 | access to local variable slice | null | E.cs:58:25:58:42 | object creation of type List | null | +| E.cs:61:23:61:25 | access to local variable str | non-null | E.cs:55:23:55:34 | access to property Current | non-null | +| E.cs:61:23:61:25 | access to local variable str | null | E.cs:55:23:55:34 | access to property Current | null | +| E.cs:70:22:70:32 | ... == ... | false | E.cs:70:22:70:24 | access to parameter arr | non-null | +| E.cs:70:22:70:32 | ... == ... | true | E.cs:70:22:70:24 | access to parameter arr | null | +| E.cs:83:13:83:24 | ... != ... | false | E.cs:83:13:83:16 | access to parameter vals | null | +| E.cs:83:13:83:24 | ... != ... | true | E.cs:83:13:83:16 | access to parameter vals | non-null | +| E.cs:83:13:83:30 | ... && ... | true | E.cs:83:13:83:24 | ... != ... | true | +| E.cs:83:13:83:30 | ... && ... | true | E.cs:83:29:83:30 | access to parameter b1 | true | +| E.cs:85:18:85:29 | ... != ... | false | E.cs:85:18:85:21 | access to parameter vals | null | +| E.cs:85:18:85:29 | ... != ... | true | E.cs:85:18:85:21 | access to parameter vals | non-null | +| E.cs:85:18:85:35 | ... && ... | true | E.cs:85:18:85:29 | ... != ... | true | +| E.cs:85:18:85:35 | ... && ... | true | E.cs:85:34:85:35 | access to parameter b2 | true | +| E.cs:120:16:120:20 | !... | false | E.cs:120:17:120:20 | access to local variable stop | true | +| E.cs:120:16:120:20 | !... | true | E.cs:120:17:120:20 | access to local variable stop | false | +| E.cs:123:20:123:24 | !... | false | E.cs:123:21:123:24 | access to local variable stop | true | +| E.cs:123:20:123:24 | !... | true | E.cs:123:21:123:24 | access to local variable stop | false | +| E.cs:123:20:123:35 | ... && ... | true | E.cs:123:20:123:24 | !... | true | +| E.cs:123:20:123:35 | ... && ... | true | E.cs:123:29:123:35 | ... < ... | true | +| E.cs:131:25:131:29 | !... | false | E.cs:131:26:131:29 | access to local variable stop | true | +| E.cs:131:25:131:29 | !... | true | E.cs:131:26:131:29 | access to local variable stop | false | +| E.cs:131:26:131:29 | access to local variable stop | false | E.cs:130:28:130:33 | ... >= ... | false | +| E.cs:131:26:131:29 | access to local variable stop | true | E.cs:130:28:130:33 | ... >= ... | true | +| E.cs:153:13:153:16 | access to local variable obj2 | non-null | E.cs:152:23:152:26 | access to parameter obj1 | non-null | +| E.cs:153:13:153:16 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | +| E.cs:153:13:153:24 | ... != ... | false | E.cs:153:13:153:16 | access to local variable obj2 | null | +| E.cs:153:13:153:24 | ... != ... | true | E.cs:153:13:153:16 | access to local variable obj2 | non-null | +| E.cs:153:13:153:54 | ... && ... | true | E.cs:153:13:153:24 | ... != ... | true | +| E.cs:153:13:153:54 | ... && ... | true | E.cs:153:29:153:54 | ... > ... | true | +| E.cs:153:29:153:32 | access to local variable obj2 | non-null | E.cs:152:23:152:26 | access to parameter obj1 | non-null | +| E.cs:153:29:153:32 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | +| E.cs:155:13:155:16 | access to local variable obj2 | non-null | E.cs:152:23:152:26 | access to parameter obj1 | non-null | +| E.cs:155:13:155:16 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | +| E.cs:159:13:159:16 | access to local variable obj2 | non-null | E.cs:152:23:152:26 | access to parameter obj1 | non-null | +| E.cs:159:13:159:16 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | +| E.cs:164:17:164:25 | ... == ... | false | E.cs:164:17:164:17 | access to parameter a | non-null | +| E.cs:164:17:164:25 | ... == ... | true | E.cs:164:17:164:17 | access to parameter a | null | +| E.cs:175:19:175:29 | ... == ... | false | E.cs:175:19:175:21 | access to parameter obj | non-null | +| E.cs:175:19:175:29 | ... == ... | true | E.cs:175:19:175:21 | access to parameter obj | null | +| E.cs:175:19:175:42 | ... ? ... : ... | true | E.cs:175:19:175:29 | ... == ... | false | +| E.cs:175:19:175:42 | ... ? ... : ... | true | E.cs:175:41:175:42 | access to parameter b1 | true | +| E.cs:176:13:176:14 | access to local variable b2 | false | E.cs:175:19:175:42 | ... ? ... : ... | false | +| E.cs:176:13:176:14 | access to local variable b2 | true | E.cs:175:19:175:42 | ... ? ... : ... | true | +| E.cs:176:13:176:22 | ... == ... | false | E.cs:176:13:176:14 | (...) ... | non-null | +| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:13:176:14 | (...) ... | null | +| E.cs:180:13:180:23 | ... == ... | false | E.cs:180:13:180:15 | access to parameter obj | non-null | +| E.cs:180:13:180:23 | ... == ... | true | E.cs:180:13:180:15 | access to parameter obj | null | +| E.cs:184:13:184:22 | ... == ... | false | E.cs:184:13:184:14 | (...) ... | non-null | +| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:13:184:14 | (...) ... | null | +| E.cs:199:9:199:9 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | +| E.cs:199:9:199:9 | access to local variable o | null | E.cs:198:17:198:29 | ... ? ... : ... | null | +| E.cs:201:11:201:11 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | +| E.cs:201:11:201:11 | access to local variable o | null | E.cs:198:17:198:29 | ... ? ... : ... | null | +| E.cs:203:11:203:11 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | +| E.cs:203:11:203:11 | access to local variable o | null | E.cs:198:17:198:29 | ... ? ... : ... | null | +| E.cs:208:13:208:23 | ... is ... | true | E.cs:208:13:208:13 | access to parameter s | non-null | +| E.cs:252:13:252:21 | ... != ... | false | E.cs:252:13:252:13 | access to parameter i | null | +| E.cs:252:13:252:21 | ... != ... | true | E.cs:252:13:252:13 | access to parameter i | non-null | +| E.cs:259:13:259:21 | ... == ... | false | E.cs:259:13:259:13 | access to parameter i | non-null | +| E.cs:259:13:259:21 | ... == ... | true | E.cs:259:13:259:13 | access to parameter i | null | +| Forwarding.cs:9:13:9:30 | !... | false | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | true | +| Forwarding.cs:9:13:9:30 | !... | true | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | false | +| Forwarding.cs:9:14:9:14 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:9:14:9:14 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | false | Forwarding.cs:9:14:9:14 | access to local variable s | non-null | +| Forwarding.cs:11:31:11:31 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:11:31:11:31 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:14:13:14:13 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:14:13:14:13 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | true | Forwarding.cs:14:13:14:13 | access to local variable s | non-null | +| Forwarding.cs:16:31:16:31 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:16:31:16:31 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:19:13:19:23 | !... | false | Forwarding.cs:19:14:19:23 | call to method IsNull | true | +| Forwarding.cs:19:13:19:23 | !... | true | Forwarding.cs:19:14:19:23 | call to method IsNull | false | +| Forwarding.cs:19:14:19:14 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:19:14:19:14 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:19:14:19:23 | call to method IsNull | false | Forwarding.cs:19:14:19:14 | access to local variable s | non-null | +| Forwarding.cs:19:14:19:23 | call to method IsNull | true | Forwarding.cs:19:14:19:14 | access to local variable s | null | +| Forwarding.cs:21:31:21:31 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:21:31:21:31 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:24:13:24:13 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:24:13:24:13 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:24:13:24:25 | call to method IsNotNull | false | Forwarding.cs:24:13:24:13 | access to local variable s | null | +| Forwarding.cs:24:13:24:25 | call to method IsNotNull | true | Forwarding.cs:24:13:24:13 | access to local variable s | non-null | +| Forwarding.cs:26:31:26:31 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:26:31:26:31 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:29:13:29:24 | call to method IsNotNull | true | Forwarding.cs:29:23:29:23 | access to local variable s | non-null | +| Forwarding.cs:29:23:29:23 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:29:23:29:23 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:31:31:31:31 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:31:31:31:31 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:34:13:34:29 | call to method IsNotNullWrong | false | Forwarding.cs:34:28:34:28 | access to local variable s | non-null | +| Forwarding.cs:34:28:34:28 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:34:28:34:28 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:36:31:36:31 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:36:31:36:31 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:39:25:39:25 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:39:25:39:25 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:40:27:40:27 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | +| Forwarding.cs:40:27:40:27 | access to local variable s | null | Forwarding.cs:7:20:7:23 | null | null | +| Forwarding.cs:45:16:45:26 | ... is ... | true | Forwarding.cs:45:16:45:16 | access to parameter o | non-null | +| Forwarding.cs:45:30:45:61 | !... | false | Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | true | +| Forwarding.cs:45:30:45:61 | !... | true | Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | false | +| Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | false | Forwarding.cs:45:52:45:60 | (...) ... | non-null | +| Forwarding.cs:45:65:45:75 | !... | false | Forwarding.cs:45:66:45:75 | call to method IsNull | true | +| Forwarding.cs:45:65:45:75 | !... | true | Forwarding.cs:45:66:45:75 | call to method IsNull | false | +| Forwarding.cs:45:66:45:75 | call to method IsNull | false | Forwarding.cs:45:66:45:66 | access to parameter o | non-null | +| Forwarding.cs:45:66:45:75 | call to method IsNull | true | Forwarding.cs:45:66:45:66 | access to parameter o | null | +| Forwarding.cs:50:13:50:23 | ... is ... | true | Forwarding.cs:50:13:50:13 | access to parameter o | non-null | +| Forwarding.cs:52:20:52:51 | !... | false | Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | true | +| Forwarding.cs:52:20:52:51 | !... | true | Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | false | +| Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | false | Forwarding.cs:52:42:52:50 | (...) ... | non-null | +| Forwarding.cs:59:13:59:21 | ... == ... | false | Forwarding.cs:59:13:59:13 | access to parameter o | non-null | +| Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:13:59:13 | access to parameter o | null | +| Forwarding.cs:68:16:68:38 | call to method IsNullOrEmpty | false | Forwarding.cs:68:37:68:37 | access to parameter s | non-null | +| Forwarding.cs:73:16:73:39 | !... | false | Forwarding.cs:73:17:73:39 | call to method IsNullOrEmpty | true | +| Forwarding.cs:73:16:73:39 | !... | true | Forwarding.cs:73:17:73:39 | call to method IsNullOrEmpty | false | +| Forwarding.cs:73:17:73:39 | call to method IsNullOrEmpty | false | Forwarding.cs:73:38:73:38 | access to parameter s | non-null | +| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | false | Forwarding.cs:78:32:78:32 | access to parameter o | non-null | +| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:32:78:32 | access to parameter o | null | +| Forwarding.cs:83:16:83:24 | ... != ... | false | Forwarding.cs:83:16:83:16 | access to parameter o | null | +| Forwarding.cs:83:16:83:24 | ... != ... | true | Forwarding.cs:83:16:83:16 | access to parameter o | non-null | +| GuardedString.cs:9:13:9:36 | !... | false | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | true | +| GuardedString.cs:9:13:9:36 | !... | true | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | +| GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | GuardedString.cs:9:35:9:35 | access to local variable s | non-null | +| GuardedString.cs:9:35:9:35 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:9:35:9:35 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:11:31:11:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:11:31:11:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:14:13:14:41 | !... | false | GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | true | +| GuardedString.cs:14:13:14:41 | !... | true | GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | false | +| GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | false | GuardedString.cs:14:40:14:40 | access to local variable s | non-null | +| GuardedString.cs:14:40:14:40 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:14:40:14:40 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:16:31:16:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:16:31:16:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:19:13:19:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:19:13:19:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:19:13:19:26 | ... == ... | true | GuardedString.cs:19:15:19:21 | access to property Length | non-null | +| GuardedString.cs:19:15:19:21 | access to property Length | non-null | GuardedString.cs:19:13:19:13 | access to local variable s | non-null | +| GuardedString.cs:19:15:19:21 | access to property Length | null | GuardedString.cs:19:13:19:13 | access to local variable s | null | +| GuardedString.cs:20:31:20:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:20:31:20:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:22:13:22:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:22:13:22:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:22:13:22:25 | ... > ... | true | GuardedString.cs:22:15:22:21 | access to property Length | non-null | +| GuardedString.cs:22:15:22:21 | access to property Length | non-null | GuardedString.cs:22:13:22:13 | access to local variable s | non-null | +| GuardedString.cs:22:15:22:21 | access to property Length | null | GuardedString.cs:22:13:22:13 | access to local variable s | null | +| GuardedString.cs:23:31:23:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:23:31:23:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:25:13:25:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:25:13:25:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:25:13:25:26 | ... >= ... | true | GuardedString.cs:25:15:25:21 | access to property Length | non-null | +| GuardedString.cs:25:15:25:21 | access to property Length | non-null | GuardedString.cs:25:13:25:13 | access to local variable s | non-null | +| GuardedString.cs:25:15:25:21 | access to property Length | null | GuardedString.cs:25:13:25:13 | access to local variable s | null | +| GuardedString.cs:26:31:26:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:26:31:26:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:28:13:28:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:28:13:28:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:28:13:28:26 | ... < ... | true | GuardedString.cs:28:15:28:21 | access to property Length | non-null | +| GuardedString.cs:28:15:28:21 | access to property Length | non-null | GuardedString.cs:28:13:28:13 | access to local variable s | non-null | +| GuardedString.cs:28:15:28:21 | access to property Length | null | GuardedString.cs:28:13:28:13 | access to local variable s | null | +| GuardedString.cs:29:31:29:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:29:31:29:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:31:13:31:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:31:13:31:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:31:13:31:27 | ... <= ... | true | GuardedString.cs:31:15:31:21 | access to property Length | non-null | +| GuardedString.cs:31:15:31:21 | access to property Length | non-null | GuardedString.cs:31:13:31:13 | access to local variable s | non-null | +| GuardedString.cs:31:15:31:21 | access to property Length | null | GuardedString.cs:31:13:31:13 | access to local variable s | null | +| GuardedString.cs:32:31:32:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:32:31:32:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:34:13:34:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:34:13:34:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:34:13:34:26 | ... != ... | false | GuardedString.cs:34:15:34:21 | access to property Length | non-null | +| GuardedString.cs:34:15:34:21 | access to property Length | non-null | GuardedString.cs:34:13:34:13 | access to local variable s | non-null | +| GuardedString.cs:34:15:34:21 | access to property Length | null | GuardedString.cs:34:13:34:13 | access to local variable s | null | +| GuardedString.cs:35:31:35:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:35:31:35:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:37:31:37:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:37:31:37:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| StringConcatenation.cs:8:9:8:9 | access to local variable s | non-null | StringConcatenation.cs:7:20:7:23 | null | non-null | +| StringConcatenation.cs:8:9:8:9 | access to local variable s | null | StringConcatenation.cs:7:20:7:23 | null | null | +| StringConcatenation.cs:8:9:8:18 | ... + ... | non-null | StringConcatenation.cs:8:9:8:9 | access to local variable s | non-null | +| StringConcatenation.cs:8:9:8:18 | ... + ... | null | StringConcatenation.cs:8:9:8:9 | access to local variable s | null | +| StringConcatenation.cs:9:13:9:13 | access to local variable s | non-null | StringConcatenation.cs:8:9:8:18 | ... + ... | non-null | +| StringConcatenation.cs:9:13:9:13 | access to local variable s | null | StringConcatenation.cs:8:9:8:18 | ... + ... | null | +| StringConcatenation.cs:15:16:15:22 | ... != ... | false | StringConcatenation.cs:15:16:15:16 | access to local variable s | non-null | +| StringConcatenation.cs:22:16:22:22 | ... != ... | false | StringConcatenation.cs:22:16:22:16 | access to local variable s | non-null | +| StringConcatenation.cs:23:13:23:22 | ... + ... | non-null | StringConcatenation.cs:23:13:23:13 | access to local variable s | non-null | +| StringConcatenation.cs:23:13:23:22 | ... + ... | null | StringConcatenation.cs:23:13:23:13 | access to local variable s | null | +| StringConcatenation.cs:30:9:30:9 | access to local variable s | non-null | StringConcatenation.cs:29:20:29:24 | "abc" | non-null | +| StringConcatenation.cs:30:9:30:9 | access to local variable s | null | StringConcatenation.cs:29:20:29:24 | "abc" | null | +| StringConcatenation.cs:31:13:31:13 | access to local variable s | non-null | StringConcatenation.cs:30:9:30:17 | ... + ... | non-null | +| StringConcatenation.cs:31:13:31:13 | access to local variable s | null | StringConcatenation.cs:30:9:30:17 | ... + ... | null | diff --git a/csharp/ql/test/query-tests/Nullness/Implications.ql b/csharp/ql/test/query-tests/Nullness/Implications.ql new file mode 100644 index 00000000000..0c185b1a2dc --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/Implications.ql @@ -0,0 +1,6 @@ +import csharp +import semmle.code.csharp.controlflow.Guards + +query predicate impliesStep(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) { + Internal::impliesStep(e1, v1, e2, v2) +} diff --git a/csharp/ql/test/query-tests/Nullness/NullAlways.expected b/csharp/ql/test/query-tests/Nullness/NullAlways.expected index 22e17f701fe..1b3e73aaeef 100644 --- a/csharp/ql/test/query-tests/Nullness/NullAlways.expected +++ b/csharp/ql/test/query-tests/Nullness/NullAlways.expected @@ -1,17 +1,26 @@ -| A.cs:15:13:15:15 | access to local variable not | Variable $@ is always null here. | A.cs:12:16:12:18 | not | not | -| A.cs:30:15:30:33 | access to local variable synchronized_always | Variable $@ is always null here. | A.cs:29:16:29:34 | synchronized_always | synchronized_always | -| A.cs:77:31:77:39 | access to local variable do_always | Variable $@ is always null here. | A.cs:74:16:74:24 | do_always | do_always | -| A.cs:111:31:111:42 | access to local variable while_always | Variable $@ is always null here. | A.cs:108:16:108:27 | while_always | while_always | -| A.cs:129:9:129:18 | access to local variable array_null | Variable $@ is always null here. | A.cs:128:15:128:24 | array_null | array_null | -| A.cs:149:31:149:39 | access to local variable if_always | Variable $@ is always null here. | A.cs:146:16:146:24 | if_always | if_always | -| A.cs:169:27:169:32 | access to local variable for_ok | Variable $@ is always null here. | A.cs:163:16:163:21 | for_ok | for_ok | -| A.cs:174:31:174:40 | access to local variable for_always | Variable $@ is always null here. | A.cs:172:21:172:30 | for_always | for_always | -| A.cs:191:27:191:37 | access to local variable arrayaccess | Variable $@ is always null here. | A.cs:186:15:186:25 | arrayaccess | arrayaccess | -| A.cs:192:27:192:37 | access to local variable fieldaccess | Variable $@ is always null here. | A.cs:187:18:187:28 | fieldaccess | fieldaccess | -| A.cs:193:28:193:39 | access to local variable methodaccess | Variable $@ is always null here. | A.cs:188:16:188:27 | methodaccess | methodaccess | -| A.cs:194:27:194:36 | access to local variable methodcall | Variable $@ is always null here. | A.cs:189:16:189:25 | methodcall | methodcall | -| A.cs:247:31:247:44 | access to local variable eq_call_always | Variable $@ is always null here. | A.cs:241:11:241:24 | eq_call_always | eq_call_always | -| A.cs:258:31:258:45 | access to local variable neq_call_always | Variable $@ is always null here. | A.cs:244:11:244:25 | neq_call_always | neq_call_always | +| A.cs:8:15:8:32 | access to local variable synchronizedAlways | Variable $@ is always null here. | A.cs:7:16:7:33 | synchronizedAlways | synchronizedAlways | +| A.cs:17:9:17:17 | access to local variable arrayNull | Variable $@ is always null here. | A.cs:16:15:16:23 | arrayNull | arrayNull | +| A.cs:31:27:31:37 | access to local variable arrayAccess | Variable $@ is always null here. | A.cs:26:15:26:25 | arrayAccess | arrayAccess | +| A.cs:32:27:32:37 | access to local variable fieldAccess | Variable $@ is always null here. | A.cs:27:18:27:28 | fieldAccess | fieldAccess | +| A.cs:33:28:33:39 | access to local variable methodAccess | Variable $@ is always null here. | A.cs:28:16:28:27 | methodAccess | methodAccess | +| A.cs:34:27:34:36 | access to local variable methodCall | Variable $@ is always null here. | A.cs:29:16:29:25 | methodCall | methodCall | | Assert.cs:15:27:15:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | | Assert.cs:23:27:23:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | | Assert.cs:31:27:31:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:47:27:47:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:51:27:51:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| B.cs:13:13:13:24 | access to local variable eqCallAlways | Variable $@ is always null here. | B.cs:7:11:7:22 | eqCallAlways | eqCallAlways | +| B.cs:24:13:24:25 | access to local variable neqCallAlways | Variable $@ is always null here. | B.cs:10:11:10:23 | neqCallAlways | neqCallAlways | +| C.cs:18:13:18:13 | access to local variable o | Variable $@ is always null here. | C.cs:10:16:10:16 | o | o | +| C.cs:42:9:42:9 | access to local variable s | Variable $@ is always null here. | C.cs:40:13:40:13 | s | s | +| C.cs:57:9:57:10 | access to local variable o2 | Variable $@ is always null here. | C.cs:55:13:55:14 | o2 | o2 | +| C.cs:163:13:163:13 | access to local variable s | Variable $@ is always null here. | C.cs:152:13:152:13 | s | s | +| C.cs:197:13:197:13 | access to local variable s | Variable $@ is always null here. | C.cs:186:13:186:13 | s | s | +| C.cs:219:13:219:13 | access to local variable s | Variable $@ is always null here. | C.cs:211:13:211:13 | s | s | +| C.cs:234:9:234:9 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s | +| C.cs:238:13:238:13 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s | +| C.cs:250:9:250:9 | access to local variable a | Variable $@ is always null here. | C.cs:249:15:249:15 | a | a | +| C.cs:261:9:261:10 | access to local variable ia | Variable $@ is always null here. | C.cs:258:15:258:16 | ia | ia | +| C.cs:262:20:262:21 | access to local variable sa | Variable $@ is always null here. | C.cs:259:18:259:19 | sa | sa | +| D.cs:385:13:385:15 | access to local variable ioe | Variable $@ is always null here. | D.cs:378:19:378:21 | ioe | ioe | +| E.cs:229:13:229:13 | access to local variable x | Variable $@ is always null here. | E.cs:225:13:225:13 | x | x | diff --git a/csharp/ql/test/query-tests/Nullness/NullCheck.expected b/csharp/ql/test/query-tests/Nullness/NullCheck.expected new file mode 100644 index 00000000000..99bc29da38f --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/NullCheck.expected @@ -0,0 +1,235 @@ +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | false | true | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true | false | +| Assert.cs:22:23:22:31 | ... == ... | Assert.cs:22:23:22:23 | access to local variable s | false | false | +| Assert.cs:22:23:22:31 | ... == ... | Assert.cs:22:23:22:23 | access to local variable s | true | true | +| Assert.cs:26:23:26:31 | ... != ... | Assert.cs:26:23:26:23 | access to local variable s | false | true | +| Assert.cs:26:23:26:31 | ... != ... | Assert.cs:26:23:26:23 | access to local variable s | true | false | +| Assert.cs:30:24:30:32 | ... != ... | Assert.cs:30:24:30:24 | access to local variable s | false | true | +| Assert.cs:30:24:30:32 | ... != ... | Assert.cs:30:24:30:24 | access to local variable s | true | false | +| Assert.cs:34:24:34:32 | ... == ... | Assert.cs:34:24:34:24 | access to local variable s | false | false | +| Assert.cs:34:24:34:32 | ... == ... | Assert.cs:34:24:34:24 | access to local variable s | true | true | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | false | true | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true | false | +| Assert.cs:42:24:42:32 | ... == ... | Assert.cs:42:24:42:24 | access to local variable s | false | false | +| Assert.cs:42:24:42:32 | ... == ... | Assert.cs:42:24:42:24 | access to local variable s | true | true | +| Assert.cs:46:23:46:31 | ... == ... | Assert.cs:46:23:46:23 | access to local variable s | false | false | +| Assert.cs:46:23:46:31 | ... == ... | Assert.cs:46:23:46:23 | access to local variable s | true | true | +| Assert.cs:50:24:50:32 | ... != ... | Assert.cs:50:24:50:24 | access to local variable s | false | true | +| Assert.cs:50:24:50:32 | ... != ... | Assert.cs:50:24:50:24 | access to local variable s | true | false | +| B.cs:12:13:12:32 | call to operator == | B.cs:12:13:12:24 | access to local variable eqCallAlways | false | false | +| B.cs:12:13:12:32 | call to operator == | B.cs:12:13:12:24 | access to local variable eqCallAlways | true | true | +| B.cs:15:13:15:22 | call to operator != | B.cs:15:13:15:14 | access to local variable b2 | false | true | +| B.cs:15:13:15:22 | call to operator != | B.cs:15:13:15:14 | access to local variable b2 | true | false | +| B.cs:18:13:18:22 | call to operator == | B.cs:18:13:18:14 | access to local variable b3 | false | false | +| B.cs:18:13:18:22 | call to operator == | B.cs:18:13:18:14 | access to local variable b3 | true | true | +| B.cs:22:13:22:33 | call to operator != | B.cs:22:13:22:25 | access to local variable neqCallAlways | false | true | +| B.cs:22:13:22:33 | call to operator != | B.cs:22:13:22:25 | access to local variable neqCallAlways | true | false | +| B.cs:53:17:53:33 | ... != ... | B.cs:53:17:53:25 | (...) ... | false | true | +| B.cs:53:17:53:33 | ... != ... | B.cs:53:17:53:25 | (...) ... | true | false | +| C.cs:11:19:11:27 | ... == ... | C.cs:11:19:11:19 | access to local variable o | false | false | +| C.cs:11:19:11:27 | ... == ... | C.cs:11:19:11:19 | access to local variable o | true | true | +| C.cs:16:15:16:23 | ... != ... | C.cs:16:15:16:15 | access to local variable o | false | true | +| C.cs:16:15:16:23 | ... != ... | C.cs:16:15:16:15 | access to local variable o | true | false | +| C.cs:24:13:24:21 | ... != ... | C.cs:24:13:24:13 | access to parameter o | false | true | +| C.cs:24:13:24:21 | ... != ... | C.cs:24:13:24:13 | access to parameter o | true | false | +| C.cs:28:37:28:45 | ... == ... | C.cs:28:37:28:37 | access to parameter o | false | false | +| C.cs:28:37:28:45 | ... == ... | C.cs:28:37:28:37 | access to parameter o | true | true | +| C.cs:30:40:30:48 | ... != ... | C.cs:30:40:30:40 | access to parameter o | false | true | +| C.cs:30:40:30:48 | ... != ... | C.cs:30:40:30:40 | access to parameter o | true | false | +| C.cs:34:13:34:21 | ... == ... | C.cs:34:13:34:13 | access to parameter o | false | false | +| C.cs:34:13:34:21 | ... == ... | C.cs:34:13:34:13 | access to parameter o | true | true | +| C.cs:41:22:41:30 | ... == ... | C.cs:41:22:41:22 | access to local variable s | false | false | +| C.cs:41:22:41:30 | ... == ... | C.cs:41:22:41:22 | access to local variable s | true | true | +| C.cs:45:22:45:30 | ... != ... | C.cs:45:22:45:22 | access to local variable s | false | true | +| C.cs:45:22:45:30 | ... != ... | C.cs:45:22:45:22 | access to local variable s | true | false | +| C.cs:78:13:78:24 | call to method IsNotNull | C.cs:78:23:78:23 | access to local variable o | false | true | +| C.cs:78:13:78:24 | call to method IsNotNull | C.cs:78:23:78:23 | access to local variable o | true | false | +| C.cs:82:14:82:22 | call to method IsNull | C.cs:82:21:82:21 | access to local variable o | false | false | +| C.cs:82:14:82:22 | call to method IsNull | C.cs:82:21:82:21 | access to local variable o | true | true | +| C.cs:89:13:89:23 | ... is ... | C.cs:89:13:89:13 | access to local variable o | true | false | +| C.cs:114:22:114:36 | ... == ... | C.cs:114:22:114:28 | access to local variable colours | false | false | +| C.cs:114:22:114:36 | ... == ... | C.cs:114:22:114:28 | access to local variable colours | true | true | +| C.cs:121:13:121:28 | ... == ... | C.cs:121:13:121:20 | access to local variable children | false | false | +| C.cs:121:13:121:28 | ... == ... | C.cs:121:13:121:20 | access to local variable children | true | true | +| C.cs:130:13:130:38 | ... == ... | C.cs:130:14:130:29 | ... = ... | false | false | +| C.cs:130:13:130:38 | ... == ... | C.cs:130:14:130:29 | ... = ... | true | true | +| C.cs:146:13:146:39 | ... != ... | C.cs:146:14:146:30 | ... = ... | false | true | +| C.cs:146:13:146:39 | ... != ... | C.cs:146:14:146:30 | ... = ... | true | false | +| C.cs:158:16:158:24 | ... != ... | C.cs:158:16:158:16 | access to local variable s | false | true | +| C.cs:158:16:158:24 | ... != ... | C.cs:158:16:158:16 | access to local variable s | true | false | +| C.cs:166:16:166:24 | ... != ... | C.cs:166:16:166:16 | access to local variable s | false | true | +| C.cs:166:16:166:24 | ... != ... | C.cs:166:16:166:16 | access to local variable s | true | false | +| C.cs:173:16:173:24 | ... != ... | C.cs:173:16:173:16 | access to local variable s | false | true | +| C.cs:173:16:173:24 | ... != ... | C.cs:173:16:173:16 | access to local variable s | true | false | +| C.cs:187:16:187:24 | ... != ... | C.cs:187:16:187:16 | access to local variable s | false | true | +| C.cs:187:16:187:24 | ... != ... | C.cs:187:16:187:16 | access to local variable s | true | false | +| C.cs:212:13:212:21 | ... != ... | C.cs:212:13:212:13 | access to local variable s | false | true | +| C.cs:212:13:212:21 | ... != ... | C.cs:212:13:212:13 | access to local variable s | true | false | +| C.cs:218:13:218:21 | ... == ... | C.cs:218:13:218:13 | access to local variable s | false | false | +| C.cs:218:13:218:21 | ... == ... | C.cs:218:13:218:13 | access to local variable s | true | true | +| C.cs:222:13:222:21 | ... != ... | C.cs:222:13:222:13 | access to local variable s | false | true | +| C.cs:222:13:222:21 | ... != ... | C.cs:222:13:222:13 | access to local variable s | true | false | +| C.cs:230:22:230:30 | ... != ... | C.cs:230:22:230:22 | access to local variable s | false | true | +| C.cs:230:22:230:30 | ... != ... | C.cs:230:22:230:22 | access to local variable s | true | false | +| C.cs:236:24:236:32 | ... == ... | C.cs:236:24:236:24 | access to local variable s | false | false | +| C.cs:236:24:236:32 | ... == ... | C.cs:236:24:236:24 | access to local variable s | true | true | +| D.cs:28:13:28:25 | ... != ... | D.cs:28:13:28:17 | access to parameter param | false | true | +| D.cs:28:13:28:25 | ... != ... | D.cs:28:13:28:17 | access to parameter param | true | false | +| D.cs:37:13:37:23 | ... is ... | D.cs:37:13:37:13 | access to parameter x | true | false | +| D.cs:38:13:38:21 | ... == ... | D.cs:38:13:38:13 | access to parameter x | false | false | +| D.cs:38:13:38:21 | ... == ... | D.cs:38:13:38:13 | access to parameter x | true | true | +| D.cs:39:16:39:24 | ... == ... | D.cs:39:16:39:16 | access to parameter x | false | false | +| D.cs:39:16:39:24 | ... == ... | D.cs:39:16:39:16 | access to parameter x | true | true | +| D.cs:45:13:45:22 | ... != ... | D.cs:45:13:45:14 | access to local variable o1 | false | true | +| D.cs:45:13:45:22 | ... != ... | D.cs:45:13:45:14 | access to local variable o1 | true | false | +| D.cs:48:13:48:24 | ... is ... | D.cs:48:13:48:14 | access to local variable o2 | true | false | +| D.cs:51:13:51:44 | ... != ... | D.cs:51:14:51:35 | ... = ... | false | true | +| D.cs:51:13:51:44 | ... != ... | D.cs:51:14:51:35 | ... = ... | true | false | +| D.cs:55:23:55:32 | ... != ... | D.cs:55:23:55:24 | access to local variable o4 | false | true | +| D.cs:55:23:55:32 | ... != ... | D.cs:55:23:55:24 | access to local variable o4 | true | false | +| D.cs:58:19:58:28 | ... != ... | D.cs:58:19:58:20 | access to local variable o4 | false | true | +| D.cs:58:19:58:28 | ... != ... | D.cs:58:19:58:20 | access to local variable o4 | true | false | +| D.cs:59:13:59:22 | ... != ... | D.cs:59:13:59:14 | access to local variable o5 | false | true | +| D.cs:59:13:59:22 | ... != ... | D.cs:59:13:59:14 | access to local variable o5 | true | false | +| D.cs:61:13:61:22 | ... != ... | D.cs:61:13:61:14 | access to local variable o4 | false | true | +| D.cs:61:13:61:22 | ... != ... | D.cs:61:13:61:14 | access to local variable o4 | true | false | +| D.cs:65:14:65:29 | call to method CustomIsNull | D.cs:65:27:65:28 | access to local variable o6 | false | false | +| D.cs:65:14:65:29 | call to method CustomIsNull | D.cs:65:27:65:28 | access to local variable o6 | true | true | +| D.cs:69:18:69:27 | ... != ... | D.cs:69:18:69:19 | access to local variable o7 | false | true | +| D.cs:69:18:69:27 | ... != ... | D.cs:69:18:69:19 | access to local variable o7 | true | false | +| D.cs:76:21:76:30 | ... == ... | D.cs:76:21:76:22 | access to local variable o8 | false | false | +| D.cs:76:21:76:30 | ... == ... | D.cs:76:21:76:22 | access to local variable o8 | true | true | +| D.cs:110:26:110:35 | ... != ... | D.cs:110:26:110:27 | access to local variable xs | false | true | +| D.cs:110:26:110:35 | ... != ... | D.cs:110:26:110:27 | access to local variable xs | true | false | +| D.cs:118:13:118:21 | ... == ... | D.cs:118:13:118:13 | access to local variable x | false | false | +| D.cs:118:13:118:21 | ... == ... | D.cs:118:13:118:13 | access to local variable x | true | true | +| D.cs:119:13:119:21 | ... == ... | D.cs:119:13:119:13 | access to local variable x | false | false | +| D.cs:119:13:119:21 | ... == ... | D.cs:119:13:119:13 | access to local variable x | true | true | +| D.cs:127:20:127:28 | ... == ... | D.cs:127:20:127:20 | access to parameter a | false | false | +| D.cs:127:20:127:28 | ... == ... | D.cs:127:20:127:20 | access to parameter a | true | true | +| D.cs:128:20:128:28 | ... == ... | D.cs:128:20:128:20 | access to parameter b | false | false | +| D.cs:128:20:128:28 | ... == ... | D.cs:128:20:128:20 | access to parameter b | true | true | +| D.cs:139:13:139:21 | ... != ... | D.cs:139:13:139:13 | access to parameter a | false | true | +| D.cs:139:13:139:21 | ... != ... | D.cs:139:13:139:13 | access to parameter a | true | false | +| D.cs:152:17:152:27 | ... != ... | D.cs:152:17:152:19 | access to parameter obj | false | true | +| D.cs:152:17:152:27 | ... != ... | D.cs:152:17:152:19 | access to parameter obj | true | false | +| D.cs:196:13:196:21 | ... == ... | D.cs:196:13:196:13 | access to local variable o | false | false | +| D.cs:196:13:196:21 | ... == ... | D.cs:196:13:196:13 | access to local variable o | true | true | +| D.cs:206:17:206:25 | ... == ... | D.cs:206:17:206:17 | access to local variable e | false | false | +| D.cs:206:17:206:25 | ... == ... | D.cs:206:17:206:17 | access to local variable e | true | true | +| D.cs:212:18:212:26 | ... == ... | D.cs:212:18:212:18 | access to local variable n | false | false | +| D.cs:212:18:212:26 | ... == ... | D.cs:212:18:212:18 | access to local variable n | true | true | +| D.cs:216:13:216:22 | ... == ... | D.cs:216:13:216:14 | access to local variable o3 | false | false | +| D.cs:216:13:216:22 | ... == ... | D.cs:216:13:216:14 | access to local variable o3 | true | true | +| D.cs:221:13:221:22 | ... == ... | D.cs:221:13:221:14 | access to local variable o4 | false | false | +| D.cs:221:13:221:22 | ... == ... | D.cs:221:13:221:14 | access to local variable o4 | true | true | +| D.cs:242:13:242:25 | ... == ... | D.cs:242:13:242:17 | access to local variable other | false | false | +| D.cs:242:13:242:25 | ... == ... | D.cs:242:13:242:17 | access to local variable other | true | true | +| D.cs:244:13:244:25 | ... != ... | D.cs:244:13:244:17 | access to local variable other | false | true | +| D.cs:244:13:244:25 | ... != ... | D.cs:244:13:244:17 | access to local variable other | true | false | +| D.cs:266:13:266:27 | ... is ... | D.cs:266:13:266:17 | access to local variable other | true | false | +| D.cs:336:13:336:23 | ... == ... | D.cs:336:13:336:15 | access to parameter obj | false | false | +| D.cs:336:13:336:23 | ... == ... | D.cs:336:13:336:15 | access to parameter obj | true | true | +| D.cs:341:13:341:23 | ... != ... | D.cs:341:13:341:15 | access to local variable msg | false | true | +| D.cs:341:13:341:23 | ... != ... | D.cs:341:13:341:15 | access to local variable msg | true | false | +| D.cs:367:27:367:35 | ... == ... | D.cs:367:27:367:27 | access to local variable b | false | false | +| D.cs:367:27:367:35 | ... == ... | D.cs:367:27:367:27 | access to local variable b | true | true | +| D.cs:382:13:382:23 | ... != ... | D.cs:382:13:382:15 | access to local variable ioe | false | true | +| D.cs:382:13:382:23 | ... != ... | D.cs:382:13:382:15 | access to local variable ioe | true | false | +| D.cs:390:20:390:28 | ... == ... | D.cs:390:20:390:20 | access to parameter a | false | false | +| D.cs:390:20:390:28 | ... == ... | D.cs:390:20:390:20 | access to parameter a | true | true | +| D.cs:397:20:397:28 | ... == ... | D.cs:397:20:397:20 | access to parameter b | false | false | +| D.cs:397:20:397:28 | ... == ... | D.cs:397:20:397:20 | access to parameter b | true | true | +| D.cs:407:14:407:22 | ... != ... | D.cs:407:14:407:14 | access to parameter x | false | true | +| D.cs:407:14:407:22 | ... != ... | D.cs:407:14:407:14 | access to parameter x | true | false | +| D.cs:407:27:407:35 | ... == ... | D.cs:407:27:407:27 | access to parameter y | false | false | +| D.cs:407:27:407:35 | ... == ... | D.cs:407:27:407:27 | access to parameter y | true | true | +| D.cs:407:42:407:50 | ... == ... | D.cs:407:42:407:42 | access to parameter x | false | false | +| D.cs:407:42:407:50 | ... == ... | D.cs:407:42:407:42 | access to parameter x | true | true | +| D.cs:407:55:407:63 | ... != ... | D.cs:407:55:407:55 | access to parameter y | false | true | +| D.cs:407:55:407:63 | ... != ... | D.cs:407:55:407:55 | access to parameter y | true | false | +| D.cs:409:13:409:21 | ... != ... | D.cs:409:13:409:13 | access to parameter x | false | true | +| D.cs:409:13:409:21 | ... != ... | D.cs:409:13:409:13 | access to parameter x | true | false | +| D.cs:411:13:411:21 | ... != ... | D.cs:411:13:411:13 | access to parameter y | false | true | +| D.cs:411:13:411:21 | ... != ... | D.cs:411:13:411:13 | access to parameter y | true | false | +| E.cs:10:34:10:54 | ... != ... | E.cs:10:35:10:45 | ... = ... | false | true | +| E.cs:10:34:10:54 | ... != ... | E.cs:10:35:10:45 | ... = ... | true | false | +| E.cs:12:32:12:52 | ... != ... | E.cs:12:33:12:43 | ... = ... | false | true | +| E.cs:12:32:12:52 | ... != ... | E.cs:12:33:12:43 | ... = ... | true | false | +| E.cs:20:19:20:28 | ... == ... | E.cs:20:19:20:20 | access to local variable s1 | false | false | +| E.cs:20:19:20:28 | ... == ... | E.cs:20:19:20:20 | access to local variable s1 | true | true | +| E.cs:21:13:21:22 | ... == ... | E.cs:21:13:21:14 | access to local variable s2 | false | false | +| E.cs:21:13:21:22 | ... == ... | E.cs:21:13:21:14 | access to local variable s2 | true | true | +| E.cs:24:19:24:28 | ... == ... | E.cs:24:19:24:20 | access to local variable s1 | false | false | +| E.cs:24:19:24:28 | ... == ... | E.cs:24:19:24:20 | access to local variable s1 | true | true | +| E.cs:26:13:26:22 | ... != ... | E.cs:26:13:26:14 | access to local variable s2 | false | true | +| E.cs:26:13:26:22 | ... != ... | E.cs:26:13:26:14 | access to local variable s2 | true | false | +| E.cs:70:22:70:32 | ... == ... | E.cs:70:22:70:24 | access to parameter arr | false | false | +| E.cs:70:22:70:32 | ... == ... | E.cs:70:22:70:24 | access to parameter arr | true | true | +| E.cs:83:13:83:24 | ... != ... | E.cs:83:13:83:16 | access to parameter vals | false | true | +| E.cs:83:13:83:24 | ... != ... | E.cs:83:13:83:16 | access to parameter vals | true | false | +| E.cs:85:18:85:29 | ... != ... | E.cs:85:18:85:21 | access to parameter vals | false | true | +| E.cs:85:18:85:29 | ... != ... | E.cs:85:18:85:21 | access to parameter vals | true | false | +| E.cs:153:13:153:24 | ... != ... | E.cs:153:13:153:16 | access to local variable obj2 | false | true | +| E.cs:153:13:153:24 | ... != ... | E.cs:153:13:153:16 | access to local variable obj2 | true | false | +| E.cs:164:17:164:25 | ... == ... | E.cs:164:17:164:17 | access to parameter a | false | false | +| E.cs:164:17:164:25 | ... == ... | E.cs:164:17:164:17 | access to parameter a | true | true | +| E.cs:175:19:175:29 | ... == ... | E.cs:175:19:175:21 | access to parameter obj | false | false | +| E.cs:175:19:175:29 | ... == ... | E.cs:175:19:175:21 | access to parameter obj | true | true | +| E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | false | false | +| E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | true | true | +| E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | false | false | +| E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | true | true | +| E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | false | false | +| E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | true | true | +| E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | non-null | false | +| E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | null | true | +| E.cs:208:13:208:23 | ... is ... | E.cs:208:13:208:13 | access to parameter s | true | false | +| E.cs:252:13:252:21 | ... != ... | E.cs:252:13:252:13 | access to parameter i | false | true | +| E.cs:252:13:252:21 | ... != ... | E.cs:252:13:252:13 | access to parameter i | true | false | +| E.cs:259:13:259:21 | ... == ... | E.cs:259:13:259:13 | access to parameter i | false | false | +| E.cs:259:13:259:21 | ... == ... | E.cs:259:13:259:13 | access to parameter i | true | true | +| 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 | +| Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | false | false | +| Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | true | true | +| Forwarding.cs:24:13:24:25 | call to method IsNotNull | Forwarding.cs:24:13:24:13 | access to local variable s | false | true | +| Forwarding.cs:24:13:24:25 | call to method IsNotNull | Forwarding.cs:24:13:24:13 | access to local variable s | true | false | +| Forwarding.cs:29:13:29:24 | call to method IsNotNull | Forwarding.cs:29:23:29:23 | access to local variable s | true | false | +| Forwarding.cs:34:13:34:29 | call to method IsNotNullWrong | Forwarding.cs:34:28:34:28 | access to local variable s | false | false | +| Forwarding.cs:45:16:45:26 | ... is ... | Forwarding.cs:45:16:45:16 | access to parameter o | true | false | +| Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | Forwarding.cs:45:52:45:60 | (...) ... | false | false | +| Forwarding.cs:45:66:45:75 | call to method IsNull | Forwarding.cs:45:66:45:66 | access to parameter o | false | false | +| Forwarding.cs:45:66:45:75 | call to method IsNull | Forwarding.cs:45:66:45:66 | access to parameter o | true | true | +| Forwarding.cs:50:13:50:23 | ... is ... | Forwarding.cs:50:13:50:13 | access to parameter o | true | false | +| Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | Forwarding.cs:52:42:52:50 | (...) ... | false | false | +| Forwarding.cs:59:13:59:21 | ... == ... | Forwarding.cs:59:13:59:13 | access to parameter o | false | false | +| Forwarding.cs:59:13:59:21 | ... == ... | Forwarding.cs:59:13:59:13 | access to parameter o | true | true | +| Forwarding.cs:68:16:68:38 | call to method IsNullOrEmpty | Forwarding.cs:68:37:68:37 | access to parameter s | false | false | +| Forwarding.cs:73:17:73:39 | call to method IsNullOrEmpty | Forwarding.cs:73:38:73:38 | access to parameter s | false | false | +| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | Forwarding.cs:78:32:78:32 | access to parameter o | false | false | +| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | Forwarding.cs:78:32:78:32 | access to parameter o | true | true | +| Forwarding.cs:83:16:83:24 | ... != ... | Forwarding.cs:83:16:83:16 | access to parameter o | false | true | +| Forwarding.cs:83:16:83:24 | ... != ... | Forwarding.cs:83:16:83:16 | access to parameter o | true | false | +| GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | GuardedString.cs:9:35:9:35 | access to local variable s | false | false | +| GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | GuardedString.cs:14:40:14:40 | access to local variable s | false | false | +| GuardedString.cs:19:13:19:13 | access to local variable s | GuardedString.cs:19:13:19:13 | access to local variable s | non-null | false | +| GuardedString.cs:19:13:19:13 | access to local variable s | GuardedString.cs:19:13:19:13 | access to local variable s | null | true | +| GuardedString.cs:19:13:19:26 | ... == ... | GuardedString.cs:19:15:19:21 | access to property Length | true | false | +| GuardedString.cs:22:13:22:13 | access to local variable s | GuardedString.cs:22:13:22:13 | access to local variable s | non-null | false | +| GuardedString.cs:22:13:22:13 | access to local variable s | GuardedString.cs:22:13:22:13 | access to local variable s | null | true | +| GuardedString.cs:22:13:22:25 | ... > ... | GuardedString.cs:22:15:22:21 | access to property Length | true | false | +| GuardedString.cs:25:13:25:13 | access to local variable s | GuardedString.cs:25:13:25:13 | access to local variable s | non-null | false | +| GuardedString.cs:25:13:25:13 | access to local variable s | GuardedString.cs:25:13:25:13 | access to local variable s | null | true | +| GuardedString.cs:25:13:25:26 | ... >= ... | GuardedString.cs:25:15:25:21 | access to property Length | true | false | +| GuardedString.cs:28:13:28:13 | access to local variable s | GuardedString.cs:28:13:28:13 | access to local variable s | non-null | false | +| GuardedString.cs:28:13:28:13 | access to local variable s | GuardedString.cs:28:13:28:13 | access to local variable s | null | true | +| GuardedString.cs:28:13:28:26 | ... < ... | GuardedString.cs:28:15:28:21 | access to property Length | true | false | +| GuardedString.cs:31:13:31:13 | access to local variable s | GuardedString.cs:31:13:31:13 | access to local variable s | non-null | false | +| GuardedString.cs:31:13:31:13 | access to local variable s | GuardedString.cs:31:13:31:13 | access to local variable s | null | true | +| GuardedString.cs:31:13:31:27 | ... <= ... | GuardedString.cs:31:15:31:21 | access to property Length | true | false | +| GuardedString.cs:34:13:34:13 | access to local variable s | GuardedString.cs:34:13:34:13 | access to local variable s | non-null | false | +| GuardedString.cs:34:13:34:13 | access to local variable s | GuardedString.cs:34:13:34:13 | access to local variable s | null | true | +| GuardedString.cs:34:13:34:26 | ... != ... | GuardedString.cs:34:15:34:21 | access to property Length | false | false | +| StringConcatenation.cs:15:16:15:22 | ... != ... | StringConcatenation.cs:15:16:15:16 | access to local variable s | false | false | +| StringConcatenation.cs:22:16:22:22 | ... != ... | StringConcatenation.cs:22:16:22:16 | access to local variable s | false | false | diff --git a/csharp/ql/test/query-tests/Nullness/NullCheck.ql b/csharp/ql/test/query-tests/Nullness/NullCheck.ql new file mode 100644 index 00000000000..4dbd80b7877 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/NullCheck.ql @@ -0,0 +1,5 @@ +import csharp +import semmle.code.csharp.controlflow.Guards + +from DereferenceableExpr de, AbstractValue v, boolean isNull +select de.getANullCheck(v, isNull), de, v, isNull diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index f0feb2a5797..e3929952d1e 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -1,8 +1,44 @@ -| A.cs:85:31:85:39 | access to local variable do_maybe1 | Variable $@ may be null here. | A.cs:82:16:82:24 | do_maybe1 | do_maybe1 | -| A.cs:92:31:92:38 | access to local variable do_maybe | Variable $@ may be null here. | A.cs:89:16:89:23 | do_maybe | do_maybe | -| A.cs:120:31:120:41 | access to local variable while_maybe | Variable $@ may be null here. | A.cs:117:16:117:26 | while_maybe | while_maybe | -| A.cs:158:27:158:34 | access to local variable if_maybe | Variable $@ may be null here. | A.cs:153:16:153:23 | if_maybe | if_maybe | -| A.cs:180:31:180:39 | access to local variable for_maybe | Variable $@ may be null here. | A.cs:178:21:178:29 | for_maybe | for_maybe | +| C.cs:64:9:64:10 | access to local variable o1 | Variable $@ may be null here. | C.cs:62:13:62:14 | o1 | o1 | +| C.cs:68:9:68:10 | access to local variable o2 | Variable $@ may be null here. | C.cs:66:13:66:14 | o2 | o2 | +| C.cs:96:15:96:15 | access to local variable o | Variable $@ may be null here. | C.cs:95:13:95:13 | o | o | +| C.cs:171:13:171:13 | access to local variable s | Variable $@ may be null here. | C.cs:152:13:152:13 | s | s | +| C.cs:178:13:178:13 | access to local variable s | Variable $@ may be null here. | C.cs:152:13:152:13 | s | s | +| C.cs:204:13:204:13 | access to local variable s | Variable $@ may be null here. | C.cs:186:13:186:13 | s | s | +| C.cs:224:9:224:9 | access to local variable s | Variable $@ may be null here. | C.cs:211:13:211:13 | s | s | +| C.cs:243:13:243:13 | access to local variable s | Variable $@ may be null here. | C.cs:229:16:229:16 | s | s | +| D.cs:60:13:60:14 | access to local variable o4 | Variable $@ may be null here. | D.cs:54:13:54:14 | o4 | o4 | +| D.cs:62:13:62:14 | access to local variable o5 | Variable $@ may be null here. | D.cs:58:13:58:14 | o5 | o5 | +| D.cs:73:13:73:14 | access to local variable o7 | Variable $@ may be null here. | D.cs:68:13:68:14 | o7 | o7 | +| D.cs:78:13:78:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | +| D.cs:80:13:80:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | +| D.cs:82:13:82:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | +| D.cs:84:13:84:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | +| D.cs:91:13:91:14 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | +| D.cs:94:21:94:22 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | +| D.cs:98:21:98:22 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | +| D.cs:105:19:105:20 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | +| D.cs:171:9:171:11 | access to local variable obj | Variable $@ may be null here. | D.cs:163:16:163:18 | obj | obj | +| D.cs:245:13:245:13 | access to local variable o | Variable $@ may be null here. | D.cs:228:16:228:16 | o | o | +| D.cs:247:13:247:13 | access to local variable o | Variable $@ may be null here. | D.cs:228:16:228:16 | o | o | +| D.cs:253:13:253:14 | access to local variable o2 | Variable $@ may be null here. | D.cs:249:13:249:14 | o2 | o2 | +| D.cs:267:13:267:13 | access to local variable o | Variable $@ may be null here. | D.cs:258:16:258:16 | o | o | +| D.cs:291:13:291:13 | access to local variable o | Variable $@ may be null here. | D.cs:258:16:258:16 | o | o | +| D.cs:294:13:294:13 | access to local variable o | Variable $@ may be null here. | D.cs:258:16:258:16 | o | o | +| D.cs:300:17:300:20 | access to local variable prev | Variable $@ may be null here. | D.cs:296:16:296:19 | prev | prev | +| D.cs:313:17:313:17 | access to local variable s | Variable $@ may be null here. | D.cs:304:16:304:16 | s | s | +| D.cs:324:9:324:9 | access to local variable r | Variable $@ may be null here. | D.cs:316:16:316:16 | r | r | +| D.cs:356:13:356:13 | access to local variable a | Variable $@ may be null here. | D.cs:351:15:351:15 | a | a | +| D.cs:363:13:363:16 | access to local variable last | Variable $@ may be null here. | D.cs:360:20:360:23 | last | last | +| D.cs:372:13:372:13 | access to local variable b | Variable $@ may be null here. | D.cs:366:15:366:15 | b | b | +| E.cs:12:38:12:39 | access to local variable a2 | Variable $@ may be null here. | E.cs:9:18:9:19 | a2 | a2 | +| E.cs:14:13:14:14 | access to local variable a3 | Variable $@ may be null here. | E.cs:11:16:11:17 | a3 | a3 | +| E.cs:27:13:27:14 | access to local variable s1 | Variable $@ may be null here. | E.cs:19:13:19:14 | s1 | s1 | +| E.cs:35:9:35:12 | access to local variable last | Variable $@ may be null here. | E.cs:32:16:32:19 | last | last | +| E.cs:43:13:43:16 | access to local variable last | Variable $@ may be null here. | E.cs:32:16:32:19 | last | last | +| E.cs:61:13:61:17 | access to local variable slice | Variable $@ may be null here. | E.cs:51:22:51:26 | slice | slice | +| E.cs:112:13:112:16 | access to local variable arr2 | Variable $@ may be null here. | E.cs:107:15:107:18 | arr2 | arr2 | +| E.cs:125:33:125:35 | access to local variable obj | Variable $@ may be null here. | E.cs:119:13:119:15 | obj | obj | +| E.cs:218:9:218:9 | access to local variable x | Variable $@ may be null here. | E.cs:215:13:215:13 | x | x | | Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ may be null here. | Forwarding.cs:7:16:7:16 | s | s | | Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ may be null here. | Forwarding.cs:7:16:7:16 | s | s | | GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here. | GuardedString.cs:7:16:7:16 | s | s | diff --git a/csharp/ql/test/query-tests/Nullness/StringConcatenation.cs b/csharp/ql/test/query-tests/Nullness/StringConcatenation.cs index 3ff140d9286..394ea907769 100644 --- a/csharp/ql/test/query-tests/Nullness/StringConcatenation.cs +++ b/csharp/ql/test/query-tests/Nullness/StringConcatenation.cs @@ -6,14 +6,14 @@ class StringsTest { string s = null; s += "abc"; - s = s.Trim(); // OK + s = s.Trim(); // GOOD } void StringMaybeNull() { string s = null; while (s != "") - s = s.Trim(); // Maybe null + s = s.Trim(); // BAD (maybe) } void StringNotNull() @@ -21,13 +21,13 @@ class StringsTest string s = null; while (s != "") s += "abc"; - s = s.Trim(); // OK (s == "") + s = s.Trim(); // GOOD } void StringNotAssignedNull() { string s = "abc"; s += null; - s = s.Trim(); // OK + s = s.Trim(); // GOOD } } From 80144a00c84fab4228a91a0feee24f94bed18b09 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 16 Nov 2018 14:39:55 +0100 Subject: [PATCH 2/8] C#: Update nullness analyses Port the SSA-based logic from the Java nullness analyses. --- csharp/ql/src/CSI/NullAlways.qhelp | 32 +- csharp/ql/src/CSI/NullAlways.ql | 10 +- csharp/ql/src/CSI/NullAlwaysBad.cs | 13 + csharp/ql/src/CSI/NullAlwaysGood.cs | 13 + csharp/ql/src/CSI/NullMaybe.qhelp | 34 +- csharp/ql/src/CSI/NullMaybe.ql | 13 +- csharp/ql/src/CSI/NullMaybeBad.cs | 15 + csharp/ql/src/CSI/NullMaybeGood.cs | 16 + .../semmle/code/csharp/controlflow/Guards.qll | 112 ++- .../semmle/code/csharp/dataflow/Nullness.qll | 791 ++++++++---------- .../src/semmle/code/csharp/dataflow/SSA.qll | 12 +- .../controlflow/guards/GuardedExpr.expected | 1 + .../controlflow/guards/Implications.expected | 60 ++ csharp/ql/test/query-tests/Nullness/A.cs | 2 +- csharp/ql/test/query-tests/Nullness/C.cs | 4 +- csharp/ql/test/query-tests/Nullness/D.cs | 34 +- csharp/ql/test/query-tests/Nullness/E.cs | 30 +- .../test/query-tests/Nullness/Forwarding.cs | 2 +- .../Nullness/Implications.expected | 652 +++++++++++++++ .../query-tests/Nullness/NullAlways.expected | 64 +- .../query-tests/Nullness/NullAlwaysBad.cs | 13 + .../query-tests/Nullness/NullAlwaysGood.cs | 13 + .../query-tests/Nullness/NullCheck.expected | 10 + .../query-tests/Nullness/NullMaybe.expected | 127 ++- .../test/query-tests/Nullness/NullMaybeBad.cs | 18 + .../query-tests/Nullness/NullMaybeGood.cs | 19 + 26 files changed, 1527 insertions(+), 583 deletions(-) create mode 100644 csharp/ql/src/CSI/NullAlwaysBad.cs create mode 100644 csharp/ql/src/CSI/NullAlwaysGood.cs create mode 100644 csharp/ql/src/CSI/NullMaybeBad.cs create mode 100644 csharp/ql/src/CSI/NullMaybeGood.cs create mode 100644 csharp/ql/test/query-tests/Nullness/NullAlwaysBad.cs create mode 100644 csharp/ql/test/query-tests/Nullness/NullAlwaysGood.cs create mode 100644 csharp/ql/test/query-tests/Nullness/NullMaybeBad.cs create mode 100644 csharp/ql/test/query-tests/Nullness/NullMaybeGood.cs diff --git a/csharp/ql/src/CSI/NullAlways.qhelp b/csharp/ql/src/CSI/NullAlways.qhelp index cac80ba8df4..5d9fb4a78eb 100644 --- a/csharp/ql/src/CSI/NullAlways.qhelp +++ b/csharp/ql/src/CSI/NullAlways.qhelp @@ -2,13 +2,39 @@ "-//Semmle//qhelp//EN" "qhelp.dtd"> + + -

If a variable is dereferenced, and the variable has a null value on all possible execution paths -leading to the dereferencing, it is guaranteed to result in a NullReferenceException. +

If a variable is dereferenced, and the variable has a null +value on all possible execution paths leading to the dereferencing, the dereferencing is +guaranteed to result in a NullReferenceException.

-

Examine the code to check for possible errors.

+ +

Ensure that the variable does not have a null value when it is dereferenced. +

+
+ +

+In the following examples, the condition s.Length > 0 is only +executed if s is null. +

+ + + +

+In the revised example, the condition is guarded correctly by using && instead of +||. +

+ + +
+ + +
  • Microsoft, NullReferenceException Class.
  • + +
    diff --git a/csharp/ql/src/CSI/NullAlways.ql b/csharp/ql/src/CSI/NullAlways.ql index 207b743ca15..7bd40b38941 100644 --- a/csharp/ql/src/CSI/NullAlways.ql +++ b/csharp/ql/src/CSI/NullAlways.ql @@ -1,9 +1,9 @@ /** * @name Dereferenced variable is always null - * @description Finds uses of a variable that may cause a NullPointerException + * @description Dereferencing a variable whose value is 'null' causes a 'NullReferenceException'. * @kind problem * @problem.severity error - * @precision medium + * @precision very-high * @id cs/dereferenced-value-is-always-null * @tags reliability * correctness @@ -14,6 +14,6 @@ import csharp import semmle.code.csharp.dataflow.Nullness -from VariableAccess access, LocalVariable var -where access = unguardedNullDereference(var) -select access, "Variable $@ is always null here.", var, var.getName() +from Dereference d, Ssa::SourceVariable v +where d.isFirstAlwaysNull(v) +select d, "Variable '$@' is always null here.", v, v.toString() diff --git a/csharp/ql/src/CSI/NullAlwaysBad.cs b/csharp/ql/src/CSI/NullAlwaysBad.cs new file mode 100644 index 00000000000..6f0d486f1c7 --- /dev/null +++ b/csharp/ql/src/CSI/NullAlwaysBad.cs @@ -0,0 +1,13 @@ +using System; + +namespace NullAlways +{ + class Bad + { + void DoPrint(string s) + { + if (s != null || s.Length > 0) + Console.WriteLine(s); + } + } +} diff --git a/csharp/ql/src/CSI/NullAlwaysGood.cs b/csharp/ql/src/CSI/NullAlwaysGood.cs new file mode 100644 index 00000000000..14002b0b2f0 --- /dev/null +++ b/csharp/ql/src/CSI/NullAlwaysGood.cs @@ -0,0 +1,13 @@ +using System; + +namespace NullAlways +{ + class Good + { + void DoPrint(string s) + { + if (s != null && s.Length > 0) + Console.WriteLine(s); + } + } +} diff --git a/csharp/ql/src/CSI/NullMaybe.qhelp b/csharp/ql/src/CSI/NullMaybe.qhelp index e6fbca67d24..5206268ebaf 100644 --- a/csharp/ql/src/CSI/NullMaybe.qhelp +++ b/csharp/ql/src/CSI/NullMaybe.qhelp @@ -2,13 +2,41 @@ "-//Semmle//qhelp//EN" "qhelp.dtd"> + + -

    If a variable is dereferenced, and the variable may have a null value on some execution paths -leading to the dereferencing, the dereferencing may result in a NullReferenceException. +

    If a variable is dereferenced, and the variable may have a null +value on some execution paths leading to the dereferencing, the dereferencing +may result in a NullReferenceException.

    -

    Examine the code to check for possible errors.

    + +

    Ensure that the variable does not have a null value when it is dereferenced. +

    +
    + +

    +In the following example, the method DoPrint() dereferences its parameter +o unconditionally, resulting in a NullReferenceException via +the call DoPrint(null). +

    + + + +

    +In the revised example, the method DoPrint() guards the dereferencing with +a null check. +

    + + + +
    + + +
  • Microsoft, NullReferenceException Class.
  • + +
    diff --git a/csharp/ql/src/CSI/NullMaybe.ql b/csharp/ql/src/CSI/NullMaybe.ql index 6985859c52a..1ee336e04a2 100644 --- a/csharp/ql/src/CSI/NullMaybe.ql +++ b/csharp/ql/src/CSI/NullMaybe.ql @@ -1,9 +1,10 @@ /** * @name Dereferenced variable may be null - * @description Finds uses of a variable that may cause a NullPointerException + * @description Dereferencing a variable whose value may be 'null' may cause a + * 'NullReferenceException'. * @kind problem * @problem.severity warning - * @precision medium + * @precision high * @id cs/dereferenced-value-may-be-null * @tags reliability * correctness @@ -14,8 +15,6 @@ import csharp import semmle.code.csharp.dataflow.Nullness -from VariableAccess access, LocalVariable var -where access = unguardedMaybeNullDereference(var) -// do not flag definite nulls here; these are already flagged by NullAlways.ql -and not access = unguardedNullDereference(var) -select access, "Variable $@ may be null here.", var, var.getName() +from Dereference d, Ssa::SourceVariable v, string msg, Element reason +where d.isFirstMaybeNull(v.getAnSsaDefinition(), msg, reason) +select d, "Variable '$@' may be null here " + msg + ".", v, v.toString(), reason, "this" diff --git a/csharp/ql/src/CSI/NullMaybeBad.cs b/csharp/ql/src/CSI/NullMaybeBad.cs new file mode 100644 index 00000000000..9950bc3c1ee --- /dev/null +++ b/csharp/ql/src/CSI/NullMaybeBad.cs @@ -0,0 +1,15 @@ +using System; + +class Bad +{ + void DoPrint(object o) + { + Console.WriteLine(o.ToString()); + } + + void M() + { + DoPrint("Hello"); + DoPrint(null); + } +} diff --git a/csharp/ql/src/CSI/NullMaybeGood.cs b/csharp/ql/src/CSI/NullMaybeGood.cs new file mode 100644 index 00000000000..04e1c48a80b --- /dev/null +++ b/csharp/ql/src/CSI/NullMaybeGood.cs @@ -0,0 +1,16 @@ +using System; + +class Good +{ + void DoPrint(object o) + { + if (o != null) + Console.WriteLine(o.ToString()); + } + + void M() + { + DoPrint("Hello"); + DoPrint(null); + } +} diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index d9bf0c81acc..ec1daabab99 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -112,6 +112,8 @@ private import AbstractValues * an expression that may evaluate to `null`. */ class DereferenceableExpr extends Expr { + private boolean isNullableType; + DereferenceableExpr() { exists(Expr e, Type t | // There is currently a bug in the extractor: the type of `x?.Length` is @@ -119,12 +121,19 @@ class DereferenceableExpr extends Expr { // `getNullEquivParent()` as a workaround this = getNullEquivParent*(e) and t = e.getType() | - t instanceof NullableType + t instanceof NullableType and + isNullableType = true or - t instanceof RefType + t instanceof RefType and + isNullableType = false ) } + /** Holds if this expression has a nullable type `T?`. */ + predicate hasNullableType() { + isNullableType = true + } + /** * Gets an expression that directly tests whether this expression is `null`. * @@ -177,9 +186,22 @@ class DereferenceableExpr extends Expr { if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then // E.g. `x is null` isNull = branch - else + else ( // E.g. `x is string` or `x is ""` - (branch = true and isNull = false) + branch = true and isNull = false + or + // E.g. `x is string` where `x` has type `string` + ie = any(IsTypeExpr ite | ite.getCheckedType() = ite.getExpr().getType()) and + branch = false and + isNull = true + ) + ) + or + this.hasNullableType() and + result = any(PropertyAccess pa | + pa.getQualifier() = this and + pa.getTarget().hasName("HasValue") and + if branch = true then isNull = false else isNull = true ) or isCustomNullCheck(result, this, v, isNull) @@ -307,19 +329,23 @@ class AccessOrCallExpr extends Expr { } private Declaration getDeclarationTarget(Expr e) { - e = any(AssignableRead ar | result = ar.getTarget()) or + e = any(AssignableAccess aa | result = aa.getTarget()) or result = e.(Call).getTarget() } private Ssa::Definition getAnSsaQualifier(Expr e) { - e = getATrackedRead(result) + e = getATrackedAccess(result) or - not e = getATrackedRead(_) and + not e = getATrackedAccess(_) and result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier()) } -private AssignableRead getATrackedRead(Ssa::Definition def) { - result = def.getARead() and +private AssignableAccess getATrackedAccess(Ssa::Definition def) { + ( + result = def.getARead() + or + result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() + ) and not def instanceof Ssa::ImplicitUntrackedDefinition } @@ -384,6 +410,15 @@ class GuardedExpr extends AccessOrCallExpr { v = v0 } + /** + * Holds if this expression must have abstract value `v`. That is, this + * expression is guarded by a structurally equal expression having abstract + * value `v`. + */ + predicate mustHaveValue(AbstractValue v) { + exists(Expr e | e = this.getAGuard(e, v)) + } + /** * Holds if this expression is guarded by expression `cond`, which must * evaluate to `b`. The expression `sub` is a sub expression of `cond` @@ -401,7 +436,7 @@ class GuardedExpr extends AccessOrCallExpr { /** An expression guarded by a `null` check. */ class NullGuardedExpr extends GuardedExpr { NullGuardedExpr() { - exists(Expr e, NullValue v | e = this.getAGuard(e, v) | not v.isNull()) + this.mustHaveValue(any(NullValue v | not v.isNull())) } } @@ -420,11 +455,28 @@ module Internal { /** Holds if expression `e` is a non-`null` value. */ predicate nonNullValue(Expr e) { - e.stripCasts() = any(Expr s | s.hasValue() and not s instanceof NullLiteral) + e instanceof ObjectCreation + or + e instanceof ArrayCreation + or + e.hasValue() and + not e instanceof NullLiteral + or + e instanceof ThisAccess + or + e instanceof AddExpr and + e.getType() instanceof StringType + } + + /** Holds if expression `e2` is a non-`null` value whenever `e1` is. */ + predicate nonNullValueImplied(Expr e1, Expr e2) { + e1 = e2.(CastExpr).getExpr() + or + e1 = e2.(AssignExpr).getRValue() } /** - * Gets the parent expression of `e` which is `null` only if `e` is `null`, + * Gets the parent expression of `e` which is `null` iff `e` is `null`, * if any. For example, `result = x?.y` and `e = x`, or `result = x + 1` * and `e = x`. */ @@ -433,6 +485,8 @@ module Internal { qe.getQualifier() = e and qe.isConditional() and ( + // The accessed declaration must have a value type in order + // for `only if` to hold result.(FieldAccess).getTarget().getType() instanceof ValueType or result.(Call).getTarget().getReturnType() instanceof ValueType @@ -444,11 +498,28 @@ module Internal { result = bao and bao.getAnOperand() = e and bao.getAnOperand() = o and + // The other operand must be provably non-null in order + // for `only if` to hold nonNullValue(o) and e != o ) } + /** + * Gets a child expression of `e` which is `null` only if `e` is `null`. + */ + Expr getANullImplyingChild(Expr e) { + e = any(QualifiableExpr qe | + qe.isConditional() and + result = qe.getQualifier() + ) + or + // In C#, `null + 1` has type `int?` with value `null` + e = any(BinaryArithmeticOperation bao | + result = bao.getAnOperand() + ) + } + /** An expression whose value may control the execution of another element. */ class Guard extends Expr { private AbstractValue val; @@ -785,6 +856,23 @@ module Internal { v1 instanceof NullValue and v2 = v1 or + g1 instanceof DereferenceableExpr and + g2 = getANullImplyingChild(g1) and + v1 = any(NullValue nv | not nv.isNull()) and + v2 = v1 + or + g2 = g1.(AssignExpr).getRValue() and + v1 = g1.getAValue() and + v2 = v1 + or + g2 = g1.(Assignment).getLValue() and + v1 = g1.getAValue() and + v2 = v1 + or + g2 = g1.(CastExpr).getExpr() and + v1 = g1.getAValue() and + v2 = v1.(NullValue) + or exists(PreSsa::Definition def | def.getDefinition().getSource() = g2 | g1 = def.getARead() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll index 03116073386..cafcee66f94 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll @@ -2,7 +2,7 @@ * Provides predicates for performing nullness analyses. * * Nullness analyses are used to identify places in a program where - * a null pointer exception (`NullReferenceException`) may be thrown. + * a `null` pointer exception (`NullReferenceException`) may be thrown. * Example: * * ``` @@ -18,493 +18,394 @@ */ import csharp +private import ControlFlow private import semmle.code.csharp.commons.Assertions private import semmle.code.csharp.commons.ComparisonTest -private import semmle.code.csharp.controlflow.Guards +private import semmle.code.csharp.controlflow.Guards as G +private import semmle.code.csharp.controlflow.Guards::AbstractValues private import semmle.code.csharp.dataflow.SSA private import semmle.code.csharp.frameworks.System +private import semmle.code.csharp.frameworks.Test /** An expression that may be `null`. */ -private class NullExpr extends Expr { - NullExpr() { - this instanceof NullLiteral or - this.(ParenthesizedExpr).getExpr() instanceof NullExpr or - this.(ConditionalExpr).getThen() instanceof NullExpr or - this.(ConditionalExpr).getElse() instanceof NullExpr +class MaybeNullExpr extends Expr { + MaybeNullExpr() { + this instanceof NullLiteral + or + this.(ConditionalExpr).getThen() instanceof MaybeNullExpr + or + this.(ConditionalExpr).getElse() instanceof MaybeNullExpr + or + this.(AssignExpr).getRValue() instanceof MaybeNullExpr + or + this.(Cast).getExpr() instanceof MaybeNullExpr } } -/** An expression that may be non-`null`. */ -private class NonNullExpr extends Expr { +/** An expression that is always `null`. */ +class AlwaysNullExpr extends Expr { + AlwaysNullExpr() { + this instanceof NullLiteral + or + this = any(ConditionalExpr ce | + ce.getThen() instanceof AlwaysNullExpr and + ce.getElse() instanceof AlwaysNullExpr + ) + or + this.(AssignExpr).getRValue() instanceof AlwaysNullExpr + or + this.(Cast).getExpr() instanceof AlwaysNullExpr + } +} + +/** An expression that is never `null`. */ +class NonNullExpr extends Expr { NonNullExpr() { - not (this instanceof NullLiteral or this instanceof ConditionalExpr or this instanceof ParenthesizedExpr) or - this.(ParenthesizedExpr).getExpr() instanceof NonNullExpr or - this.(ConditionalExpr).getThen() instanceof NonNullExpr or - this.(ConditionalExpr).getElse() instanceof NonNullExpr + G::Internal::nonNullValue(this) + or + exists(NonNullExpr mid | + G::Internal::nonNullValueImplied(mid, this) + ) + or + this instanceof G::NullGuardedExpr + or + exists(Ssa::Definition def | nonNullDef(def) | this = def.getARead()) } } -/** Gets an assignment to the variable `var` that may be `null`. */ -private AssignExpr nullSet(LocalScopeVariable var) { - var.getAnAccess() = result.getLValue() and - result.getRValue() instanceof NullExpr -} - -/** Gets an assignment to the variable `var` that may be non-`null`. */ -private Assignment nonNullSet(LocalScopeVariable var) { - var.getAnAccess() = result.getLValue() and - result.getRValue() instanceof NonNullExpr -} - -/** - * Gets an expression that will result in a `NullReferenceException` if the - * variable access `access` is `null`. - */ -private Expr nonNullAccess(LocalScopeVariableAccess access) { - access.getType() instanceof RefType - and ( - result.(ArrayAccess).getQualifier() = access or - exists (MemberAccess ma | result=ma and not ma.isConditional() | access = ma.getQualifier()) or - exists (MethodCall mc | result=mc and not mc.isConditional() | access = mc.getQualifier()) or - exists (LockStmt stmt | stmt.getExpr() = access and result = access) - ) -} - -/** - * Gets an expression that accesses the variable `var` such that it will - * result in a `NullReferenceException` if the variable is `null`. - */ -private Expr nonNullUse(LocalScopeVariable var) { - result = nonNullAccess(var.getAnAccess()) -} - -/** - * Gets a local variable declaration expression that may - * initialize the variable `var` with `null`. - */ -private LocalVariableDeclExpr initialNull(LocalVariable var) { - result.getVariable() = var and - result.getInitializer() instanceof NullExpr -} - -/** - * Gets a local variable declaration expression that may - * initialize the variable `var` with a non-`null` expression. - */ -private LocalVariableDeclExpr initialNonNull(LocalVariable var) { - result.getVariable() = var and - result.getInitializer() instanceof NonNullExpr -} - -/** - * Gets an expression that either asserts that the variable `var` - * is `null` or that may assign `null` to `var`. - */ -private Expr nullDef(LocalScopeVariable var) { - nullSet(var) = result or - initialNull(var) = result or - exists(MethodCall mc, AssertNullMethod m, Expr arg | - // E.g. `Assert.IsNull(var)` - mc = result and - mc.getTarget() = m and - mc.getArgument(m.getAssertionIndex()) = arg and - sameValue(arg, var.getAnAccess()) - ) or - exists(MethodCall mc, AssertTrueMethod m, Expr arg | - // E.g. `Assert.IsTrue(var == null)` - mc = result and - arg = nullTest(var) and - arg = mc.getArgument(m.getAssertionIndex()) and - mc.getTarget() = m - ) or - exists(MethodCall mc, AssertFalseMethod m, Expr arg | - // E.g. `Assert.IsFalse(var != null)` - mc = result and - arg = failureIsNullTest(var) and - arg = mc.getArgument(m.getAssertionIndex()) and - mc.getTarget() = m - ) -} - -/** - * Gets an expression that either asserts that the variable `var` is - * non-`null`, dereferences it, or may assign a non-`null` expression to it. - */ -private Expr nonNullDef(LocalScopeVariable var) { - nonNullSet(var) = result or - nonNullUse(var) = result or - initialNonNull(var) = result or - useAsOutParameter(var) = result or - nonNullSettingLambda(var) = result or - exists(MethodCall mc, AssertNonNullMethod m, Expr arg | - // E.g. `Assert.IsNotNull(arg)` - mc = result and - mc.getTarget() = m and - mc.getArgument(m.getAssertionIndex()) = arg and - sameValue(arg, var.getAnAccess()) - ) or - exists(MethodCall mc, AssertTrueMethod m, Expr arg | - // E.g. `Assert.IsTrue(arg != null)` - mc = result and - arg = nonNullTest(var) and - arg = mc.getArgument(m.getAssertionIndex()) and - mc.getTarget() = m - ) or - exists(MethodCall mc, AssertFalseMethod m, Expr arg | - // E.g. `Assert.IsFalse(arg == null)` - mc = result and - arg = failureIsNonNullTest(var) and - arg = mc.getArgument(m.getAssertionIndex()) and - mc.getTarget() = m - ) -} - -private Call useAsOutParameter(LocalScopeVariable var) { - exists(LocalScopeVariableAccess a | - a = result.getAnArgument() and a = var.getAnAccess() | - a.isOutArgument() or a.isRefArgument()) -} - -private AnonymousFunctionExpr nonNullSettingLambda(LocalScopeVariable var) { - result = nonNullDef(var).getEnclosingCallable() -} - -/** - * Gets a logical 'or' expression in which the expression `e` is a - * (possibly nested) operand. - */ -private LogicalOrExpr orParent(Expr e) { - e = result.getAnOperand() +/** Holds if SSA definition `def` is never `null`. */ +private predicate nonNullDef(Ssa::Definition v) { + v.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof NonNullExpr or - exists(LogicalOrExpr orexpr | result = orParent(orexpr) and e = orexpr.getAnOperand()) -} - -/** - * Gets a logical 'and' expression in which the expression `e` is a - * (possibly nested) operand. - */ -private LogicalAndExpr andParent(Expr e) { - e = result.getAnOperand() - or - exists(LogicalAndExpr andexpr | result = andParent(andexpr) and e = andexpr.getAnOperand()) -} - -/** - * Holds if variable access `access` has the "same value" as expression `expr`: - * - * - `access` is equal to `expr`, or - * - `expr` is an assignment and the `access` is its left-hand side, or - * - `expr` is an assignment and the `access` has the same value as its right-hand - * side. - */ -private predicate sameValue(Expr expr, LocalScopeVariableAccess access) { - access = expr.stripCasts() or - access = expr.(AssignExpr).getLValue() or - sameValue(expr.(AssignExpr).getRValue(), access) or - sameValue(expr.(ParenthesizedExpr).getExpr(), access) -} - -/** - * Gets an `is` expression in which the left-hand side is an access to the - * variable `var`. - */ -private Expr instanceOfTest(LocalScopeVariable var) { - exists(IsExpr e | result = e and - sameValue(e.getExpr() , var.getAnAccess())) -} - -/** - * Gets an expression performing a `null` check on the variable `var`: - * - * - either via a reference equality test with `null`, or - * - by passing it as an argument to a method that performs the test. - */ -private Expr directNullTest(LocalScopeVariable var) { - exists(ComparisonTest ct | - result = ct.getExpr() and - sameValue(ct.getAnArgument(), var.getAnAccess()) and - ct.getAnArgument() instanceof NullLiteral | - ct.(ComparisonOperationComparisonTest).getComparisonKind().isEquality() or - ct.(StaticEqualsCallComparisonTest).isReferenceEquals() or - ct.(OperatorCallComparisonTest).getComparisonKind().isEquality() - ) - or - exists(Call call, int i | result = call | - call.getRuntimeArgument(i) = var.getAnAccess() and - forex(Callable callable | - call.getARuntimeTarget() = callable | - nullTestInCallable(callable.getSourceDeclaration(), i) + exists(AssignableDefinition ad | + ad = v.(Ssa::ExplicitDefinition).getADefinition() | + ad instanceof AssignableDefinitions::IsPatternDefinition + or + ad instanceof AssignableDefinitions::TypeCasePatternDefinition + or + ad = any(AssignableDefinitions::LocalVariableDefinition d | + d.getExpr() = any(SpecificCatchClause scc).getVariableDeclExpr() + or + d.getExpr() = any(ForeachStmt fs).getAVariableDeclExpr() ) ) - or - // seems redundant, because all methods that use this method also peel ParenthesizedExpr - // However, removing this line causes an increase of memory usage - result.(ParenthesizedExpr).getExpr() = directNullTest(var) } /** - * Holds if callable `c` performs a `null` test on its `i`th argument and - * returns the result. + * Holds if the `i`th node of basic block `bb` is a dereference `d` of SSA + * definition `def`. */ -private predicate nullTestInCallable(Callable c, int i) { - exists(Parameter p | - p = c.getParameter(i) and - not p.isOverwritten() and - forex(Expr e | c.canReturn(e) | stripConditionalExpr(e) = nullTest(p)) +private predicate dereferenceAt(BasicBlock bb, int i, Ssa::Definition def, Dereference d) { + d = def.getAReadAtNode(bb.getNode(i)) +} + +/** + * Holds if `e` having abstract value `vExpr` implies that SSA definition `def` + * has abstract value `vDef`. + */ +private predicate exprImpliesSsaDef(Expr e, G::AbstractValue vExpr, Ssa::Definition def, G::AbstractValue vDef) { + exists(G::Internal::Guard g | + G::Internal::impliesSteps(e, vExpr, g, vDef) | + g = def.getARead() + or + g = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() ) - or - nullTestInLibraryMethod(c, i) } /** - * Holds if library method `m` performs a `null` test on its `i`th argument and - * returns the result. + * Holds if the `i`th node of basic block `bb` ensures that SSA definition + * `def` is not `null` in any subsequent uses. */ -private predicate nullTestInLibraryMethod(Method m, int i) { - m.fromLibrary() and - m.getName().toLowerCase().regexpMatch("(is)?null(orempty|orwhitespace)?") and - m.getReturnType() instanceof BoolType and - m.getNumberOfParameters() = 1 and - i = 0 -} - -private Expr stripConditionalExpr(Expr e) { - if e instanceof ConditionalExpr then - result = stripConditionalExpr(e.(ConditionalExpr).getThen()) or - result = stripConditionalExpr(e.(ConditionalExpr).getElse()) - else - result = e +private predicate ensureNotNullAt(BasicBlock bb, int i, Ssa::Definition def) { + exists(Expr e, G::AbstractValue v, NullValue nv | + G::Internal::asserts(bb.getNode(i).getElement(), e, v) | + exprImpliesSsaDef(e, v, def, nv) and + not nv.isNull() + ) } /** - * Gets an expression performing a non-`null` check on the variable `var`: + * Holds if the `i`th node of basic block `bb` is a dereference `d` of SSA + * definition `def`, and `def` may potentially be `null`. + */ +private predicate potentialNullDereferenceAt(BasicBlock bb, int i, Ssa::Definition def, Dereference d) { + dereferenceAt(bb, i, def, d) and + not exists(int j | ensureNotNullAt(bb, j, def) | j < i) +} + +/** + * Gets an element that tests whether a given SSA definition, `def`, is + * `null` or not. * - * - either via an inequality test with `null`, or - * - by performing an `is` test, or - * - by passing it as an argument to a method that performs the test. + * If the returned element takes the `s` branch, then `def` is guaranteed to be + * `null` if `nv.isNull()` holds, and non-`null` otherwise. */ -private Expr directNonNullTest(LocalScopeVariable var) { - exists(ComparisonTest ct | - result = ct.getExpr() and - sameValue(ct.getAnArgument(), var.getAnAccess()) and - ct.getAnArgument() instanceof NullLiteral | - ct.(ComparisonOperationComparisonTest).getComparisonKind().isInequality() or - ct.(OperatorCallComparisonTest).getComparisonKind().isInequality() +private ControlFlowElement getANullCheck(Ssa::Definition def, SuccessorTypes::ConditionalSuccessor s, NullValue nv) { + exists(Expr e, G::AbstractValue v | + v.branchImplies(result, s, e) | + exprImpliesSsaDef(e, v, def, nv) + ) +} + +/** Holds if `def` is an SSA definition that may be `null`. */ +private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason) { + // A variable compared to `null` might be `null` + exists(G::DereferenceableExpr de | + de = def.getARead() | + reason = de.getANullCheck(_, true) and + msg = "as suggested by $@ null check" and + not def instanceof Ssa::PseudoDefinition and + not nonNullDef(def) and + // Don't use a check as reason if there is a `null` assignment + not def.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof MaybeNullExpr ) or - instanceOfTest(var) = result + // A parameter might be `null` if there is a `null` argument somewhere + exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p, MaybeNullExpr arg | + pdef = def.(Ssa::ExplicitDefinition).getADefinition() | + p = pdef.getParameter().getSourceDeclaration() and + p.getAnAssignedArgument() = arg and + reason = arg and + msg = "because of $@ null argument" and + not arg.getEnclosingCallable().getEnclosingCallable*() instanceof TestMethod + ) or - exists(Call call, int i | result = call | - call.getRuntimeArgument(i) = var.getAnAccess() and - exists(call.getARuntimeTarget()) and - forall(Callable callable | - call.getARuntimeTarget() = callable | - nonNullTestInCallable(callable.getSourceDeclaration(), i) + // If the source of a variable is `null` then the variable may be `null` + exists(AssignableDefinition adef | + adef = def.(Ssa::ExplicitDefinition).getADefinition() | + adef.getSource() instanceof MaybeNullExpr and + reason = adef.getExpr() and + msg = "because of $@ assignment" + ) + or + // A variable of nullable type may be null + exists(Dereference d | + dereferenceAt(_, _, def, d) | + d.hasNullableType() and + not def instanceof Ssa::PseudoDefinition and + reason = def.getSourceVariable().getAssignable() and + msg = "because it has a nullable type" + ) +} + +/** + * Holds if `def1` being `null` in basic block `bb1` implies that `def2` might + * be null in basic block `bb2`. The SSA definitions share the same source variable. + */ +private predicate defNullImpliesStep(Ssa::Definition def1, BasicBlock bb1, Ssa::Definition def2, BasicBlock bb2) { + exists(Ssa::SourceVariable v | + defMaybeNull(v.getAnSsaDefinition(), _, _) and + def1.getSourceVariable() = v + | + def2.(Ssa::PseudoDefinition).getAnInput() = def1 and + def2.definesAt(bb2, _) + or + def2 = def1 and + not exists(Ssa::PseudoDefinition def | + def.getSourceVariable() = v and + def.definesAt(bb2, _) + ) + ) and + def1.isLiveAtEndOfBlock(bb1) and + not ensureNotNullAt(bb1, _, def1) and + bb2 = bb1.getASuccessor() and + not exists(SuccessorTypes::ConditionalSuccessor s, NullValue nv | + bb1.getLastNode() = getANullCheck(def1, s, nv).getAControlFlowNode() | + bb2 = bb1.getASuccessorByType(s) and + not nv.isNull() + ) +} + +/** + * The transitive closure of `defNullImpliesStep()` originating from `defMaybeNull()`. + * That is, those basic blocks for which the SSA definition is suspected of being `null`. + */ +private predicate defMaybeNullInBlock(Ssa::Definition def, Ssa::SourceVariable v, BasicBlock bb) { + defMaybeNull(def, _, _) and + def.definesAt(bb, _) and + v = def.getSourceVariable() + or + exists(BasicBlock mid, Ssa::Definition midDef | + defMaybeNullInBlock(midDef, v, mid) | + defNullImpliesStep(midDef, mid, def, bb) + ) +} + +/** + * Holds if `v` is a source variable that might reach a potential `null` + * dereference. + */ +private predicate nullDerefCandidateVariable(Ssa::SourceVariable v) { + exists(Ssa::Definition def, BasicBlock bb | + potentialNullDereferenceAt(bb, _, def, _) | + defMaybeNullInBlock(def, v, bb) + ) +} + +private predicate defMaybeNullInBlockOrigin(Ssa::Definition origin, Ssa::Definition def, BasicBlock bb) { + nullDerefCandidateVariable(def.getSourceVariable()) and + defMaybeNull(def, _, _) and + def.definesAt(bb, _) and + origin = def + or + exists(BasicBlock mid, Ssa::Definition midDef | + defMaybeNullInBlockOrigin(origin, midDef, mid) and + defNullImpliesStep(midDef, mid, def, bb) + ) +} + +private Ssa::Definition getAPseudoInput(Ssa::Definition def) { + result = def.(Ssa::PseudoDefinition).getAnInput() +} + +// `def.getAnUltimateDefinition()` includes inputs into uncertain +// definitions, but we only want inputs into pseudo nodes +private Ssa::Definition getAnUltimateDefinition(Ssa::Definition def) { + result = getAPseudoInput*(def) and + not result instanceof Ssa::PseudoDefinition +} + +/** + * Holds if SSA definition `def` can reach a read `ar`, without passing + * through an intermediate dereference that always (`always = true`) or + * maybe (`always = false`) throws a null reference exception. + */ +private predicate defReaches(Ssa::Definition def, AssignableRead ar, boolean always) { + ar = def.getAFirstRead() and + (always = true or always = false) + or + exists(AssignableRead mid | + defReaches(def, mid, always) | + ar = mid.getANextRead() and + not mid = any(Dereference d | + if always = true then d.isAlwaysNull(def.getSourceVariable()) else d.isMaybeNull(def, _, _) ) ) - or - // seems redundant, because all methods that use this method also peel ParenthesizedExpr - // However, removing this line causes an increase of memory usage - result.(ParenthesizedExpr).getExpr() = directNonNullTest(var) } /** - * Holds if callable `c` performs a non-`null` test on its `i`th argument and - * returns the result. + * An expression that dereferences a value. That is, an expression that may + * result in a `NullReferenceException` if the value is `null`. */ -private predicate nonNullTestInCallable(Callable c, int i) { - exists(Parameter p | - p = c.getParameter(i) and - not p.isOverwritten() and - forex(Expr e | c.canReturn(e) | stripConditionalExpr(e) = nonNullTest(p)) - ) - or - nonNullTestInLibraryMethod(c, i) -} +class Dereference extends G::DereferenceableExpr { + Dereference() { + if this.hasNullableType() then ( + // Strictly speaking, these throw `InvalidOperationException`s and not + // `NullReferenceException`s + this = any(PropertyAccess pa | pa.getTarget().hasName("Value")).getQualifier() + or + exists(Type underlyingType | + this = any(CastExpr ce | ce.getTargetType() = underlyingType).getExpr() | + underlyingType = this.getType().(NullableType).getUnderlyingType() + or + underlyingType = this.getType() and + not underlyingType instanceof NullableType + ) + ) + else ( + this = any(QualifiableExpr qe | not qe.isConditional()).getQualifier() and + not this instanceof ThisAccess and + not this instanceof BaseAccess and + not this instanceof TypeAccess + or + this = any(LockStmt stmt).getExpr() + or + this = any(ForeachStmt stmt).getIterableExpr() + or + exists(ExtensionMethodCall emc, Parameter p | + this = emc.getArgumentForParameter(p) and + p.hasExtensionMethodModifier() and + not emc.isConditional() | + p.fromSource() // assume all non-source extension methods perform a dereference + implies + exists(Ssa::ExplicitDefinition def, AssignableDefinitions::ImplicitParameterDefinition pdef | + pdef = def.getADefinition() | + p.getSourceDeclaration() = pdef.getParameter() and + def.getARead() instanceof Dereference + ) + ) + ) + } -/** - * Holds if library method `m` performs a non-`null` test on its `i`th argument - * and returns the result. - */ -private predicate nonNullTestInLibraryMethod(Method m, int i) { - m.fromLibrary() and - m.getName().toLowerCase().regexpMatch("(is)?no(t|n)null") and - m.getReturnType() instanceof BoolType and - m.getNumberOfParameters() = 1 and - i = 0 -} + private predicate isAlwaysNull0(Ssa::Definition def) { + forall(Ssa::Definition input | + input = getAnUltimateDefinition(def) | + input.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof AlwaysNullExpr + ) and + not nonNullDef(def) and + this = def.getARead() and + not this instanceof G::NullGuardedExpr + } -/** - * Gets a `null` test in a _positive_ position for the variable `var`. - */ -private Expr nullTest(LocalScopeVariable var) { - directNullTest(var) = result - or - result.(ParenthesizedExpr).getExpr() = nullTest(var) - or - exists(LogicalNotExpr notexpr | result = notexpr and - notexpr.getAChildExpr() = failureIsNullTest(var)) - or - result = andParent(nullTest(var)) - or - exists(LogicalOrExpr orexpr | result = orexpr and - orexpr.getLeftOperand() = nullTest(var) and - orexpr.getRightOperand() = nullTest(var)) -} + /** + * Holds if this expression dereferences SSA source variable `v`, which is + * always `null`. + */ + predicate isAlwaysNull(Ssa::SourceVariable v) { + this = v.getAnAccess() and + // Exclude fields, properties, and captured variables, as they may not have an + // accurate SSA representation + v.getAssignable() = any(LocalScopeVariable lsv | + strictcount(Callable c | + c = any(AssignableDefinition ad | ad.getTarget() = lsv).getEnclosingCallable() + ) = 1 + ) and + ( + forex(Ssa::Definition def0 | + this = def0.getARead() | + this.isAlwaysNull0(def0) + ) + or + exists(NullValue nv | + this.(G::GuardedExpr).mustHaveValue(nv) and + nv.isNull() + ) + ) and + not this instanceof G::NullGuardedExpr + } -/** - * Gets a non-`null` test in a _positive_ position for the variable `var`. - */ -private Expr nonNullTest(LocalScopeVariable var) { - directNonNullTest(var) = result - or - result.(ParenthesizedExpr).getExpr() = nonNullTest(var) - or - exists(LogicalNotExpr notexpr | result = notexpr and - notexpr.getAChildExpr() = failureIsNonNullTest(var)) - or - result = andParent(nonNullTest(var)) - or - exists(LogicalOrExpr orexpr | result = orexpr and - orexpr.getLeftOperand() = nonNullTest(var) and - orexpr.getRightOperand() = nonNullTest(var)) -} + /** + * Holds if this expression dereferences SSA source variable `v`, which is + * always `null`, and this expression can be reached from an SSA definition + * for `v` without passing through another such dereference. + */ + predicate isFirstAlwaysNull(Ssa::SourceVariable v) { + this.isAlwaysNull(v) and + defReaches(v.getAnSsaDefinition(), this, true) + } -/** - * Gets a non-`null` test in a _negative_ position for the variable `var`. - */ -private Expr failureIsNullTest(LocalScopeVariable var) { - directNonNullTest(var) = result - or - result.(ParenthesizedExpr).getExpr() = failureIsNullTest(var) - or - exists(LogicalNotExpr notexpr | result = notexpr and - notexpr.getAChildExpr() = failureIsNonNullTest(var)) - or - result = orParent(failureIsNullTest(var)) - or - exists(LogicalAndExpr andexpr | result = andexpr and - andexpr.getLeftOperand() = failureIsNullTest(var) and - andexpr.getRightOperand() = failureIsNullTest(var)) -} + /** + * Holds if assignable access `aa` is the first dereference of an assignable + * in a block, where it is suspected of being `null`. + */ + pragma[noinline] + private predicate nullDerefCandidate(Ssa::Definition origin) { + exists(Ssa::Definition ssa, BasicBlock bb | + potentialNullDereferenceAt(bb, _, ssa, this) | + defMaybeNullInBlockOrigin(origin, ssa, bb) + ) + } -/** - * Gets a `null` test in a _negative_ position for the variable `var`. - */ -private Expr failureIsNonNullTest(LocalScopeVariable var) { - directNullTest(var) = result - or - result.(ParenthesizedExpr).getExpr() = failureIsNonNullTest(var) - or - exists(LogicalNotExpr notexpr | result = notexpr and - notexpr.getAChildExpr() = failureIsNullTest(var)) - or - result = orParent(directNullTest(var)) - or - exists(LogicalAndExpr andexpr | result = andexpr and - andexpr.getLeftOperand() = failureIsNonNullTest(var) and - andexpr.getRightOperand() = failureIsNonNullTest(var)) -} + /** + * Holds if this expression dereferences SSA definition `def`, which may + * be `null`. + */ + predicate isMaybeNull(Ssa::Definition def, string msg, Element reason) { + exists(Ssa::Definition origin, BasicBlock bb | + this.nullDerefCandidate(origin) and + defMaybeNull(origin, msg, reason) and + potentialNullDereferenceAt(bb, _, def, this) + ) and + not this.isAlwaysNull(def.getSourceVariable()) + } -/** - * Gets an immediate successor node of the conditional node `cfgnode` where - * the condition implies that the variable `var` is `null`. - */ -private ControlFlow::Node nullBranchKill(LocalScopeVariable var, ControlFlow::Node cfgnode) { - (cfgnode.getElement() = nullTest(var) and result = cfgnode.getATrueSuccessor()) - or - (cfgnode.getElement() = failureIsNullTest(var) and result = cfgnode.getAFalseSuccessor()) -} - -/** - * Gets an immediate successor node of the conditional node `cfgnode` where - * the condition implies that the variable `var` is non-`null`. - */ -private ControlFlow::Node nonNullBranchKill(LocalScopeVariable var, ControlFlow::Node cfgnode) { - (cfgnode.getElement() = nonNullTest(var) and result = cfgnode.getATrueSuccessor()) - or - (cfgnode.getElement() = failureIsNonNullTest(var) and result = cfgnode.getAFalseSuccessor()) -} - -/** Gets a node where the variable `var` may be `null`. */ -ControlFlow::Node maybeNullNode(LocalScopeVariable var) { - result = nullDef(var).getAControlFlowNode().getASuccessor() - or - exists(ControlFlow::Node mid | - mid = maybeNullNode(var) and - not mid.getElement() = nonNullDef(var) and - mid.getASuccessor() = result and - not result = nonNullBranchKill(var, mid) - ) -} - -/** Gets a node where the variable `var` may be non-`null`. */ -ControlFlow::Node maybeNonNullNode(LocalScopeVariable var) { - result = nonNullDef(var).getAControlFlowNode().getASuccessor() - or - exists(ControlFlow::Node mid | - mid = maybeNonNullNode(var) and - not mid.getElement() = nullDef(var) and - mid.getASuccessor() = result and - not result = nullBranchKill(var, mid) - ) -} - -/** - * Gets an expression whose evaluation may be guarded by - * a non-`null` check for the variable `var`. - */ -private Expr nullGuarded(LocalScopeVariable var) { - exists(LogicalOrExpr guard | - guard.getLeftOperand() = failureIsNonNullTest(var) and - result = guard.getRightOperand()) - or - exists(LogicalAndExpr guard | - guard.getLeftOperand() = nonNullTest(var) and - result = guard.getRightOperand()) - or - exists(ConditionalExpr cond | - cond.getCondition() = nullTest(var) and - result = cond.getElse()) - or - exists(ConditionalExpr cond | - cond.getCondition() = nonNullTest(var) and - result = cond.getThen()) - or - result = any(NullGuardedExpr nge | nge = var.getAnAccess()) - or - result.getParent() = nullGuarded(var) -} - -/** - * Gets a variable access that must be non-`null` to avoid a - * `NullReferenceException`. - */ -private predicate dereferenced(LocalScopeVariableAccess access) { - exists(nonNullAccess(access)) -} - -/** - * Gets a dereferenced access to the variable `var` that - * - * - does not occur within a `null`-guarded expression, but - * - occurs within an expression where the variable may be `null`. - */ -LocalScopeVariableAccess unguardedMaybeNullDereference(LocalScopeVariable var) { - var.getAnAccess() = result and - maybeNullNode(var).getElement() = result and - dereferenced(result) and - not result = nullGuarded(var) -} - -/** - * Gets a dereferenced access to the variable `var` that - * - * - does not occur within a `null`-guarded expression, but - * - occurs within an expression where the variable may be `null`, and - * - does not occur within an expression where the variable may be non-`null`. - */ -LocalScopeVariableAccess unguardedNullDereference(LocalScopeVariable var) { - unguardedMaybeNullDereference(var) = result and - not maybeNonNullNode(var).getElement() = result + /** + * Holds if this expression dereferences SSA definition `def`, which may + * be `null`, and this expression can be reached from `def` without passing + * through another such dereference. + */ + predicate isFirstMaybeNull(Ssa::Definition def, string msg, Element reason) { + this.isMaybeNull(def, msg, reason) and + defReaches(def, this, false) + } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 9f1ccd227b7..e8fa362ebf8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -422,9 +422,18 @@ module Ssa { * Gets an SSA definition that has this variable as its underlying * source variable. */ + deprecated Definition getAnDefinition() { result.getSourceVariable() = this } + + /** + * Gets an SSA definition that has this variable as its underlying + * source variable. + */ + Definition getAnSsaDefinition() { + result.getSourceVariable() = this + } } /** Provides different types of `SourceVariable`s. */ @@ -1113,7 +1122,8 @@ module Ssa { call = succ | callable = call.getTarget() or callable = call.getTarget().(Method).getAnOverrider+() or - callable = call.getTarget().(Method).getAnUltimateImplementor() + callable = call.getTarget().(Method).getAnUltimateImplementor() or + callable = getARuntimeDelegateTarget(call) ) or pred = succ.(DelegateCreation).getArgument() diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index f3d7d039da0..054ec6f7403 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -126,6 +126,7 @@ | Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | false | | Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | non-null | | Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true | +| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | null | | Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false | | Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false | | Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case Action: | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 8634427efe3..d6bbe4af6f7 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -1,41 +1,57 @@ +| Assert.cs:9:16:9:32 | String s = ... | non-null | Assert.cs:9:16:9:16 | access to local variable s | non-null | +| Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null | | Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | | Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null | | Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null | | Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | +| Assert.cs:16:16:16:32 | String s = ... | non-null | Assert.cs:16:16:16:16 | access to local variable s | non-null | +| Assert.cs:16:16:16:32 | String s = ... | null | Assert.cs:16:16:16:16 | access to local variable s | null | | Assert.cs:17:23:17:23 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | | Assert.cs:17:23:17:23 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | | Assert.cs:18:27:18:27 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | | Assert.cs:18:27:18:27 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | +| Assert.cs:23:16:23:32 | String s = ... | non-null | Assert.cs:23:16:23:16 | access to local variable s | non-null | +| Assert.cs:23:16:23:32 | String s = ... | null | Assert.cs:23:16:23:16 | access to local variable s | null | | Assert.cs:24:26:24:26 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | | Assert.cs:24:26:24:26 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | | Assert.cs:25:27:25:27 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | | Assert.cs:25:27:25:27 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | +| Assert.cs:30:16:30:32 | String s = ... | non-null | Assert.cs:30:16:30:16 | access to local variable s | non-null | +| Assert.cs:30:16:30:32 | String s = ... | null | Assert.cs:30:16:30:16 | access to local variable s | null | | Assert.cs:31:23:31:23 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | | Assert.cs:31:23:31:23 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | | Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:31:23:31:23 | access to local variable s | non-null | | Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:31:23:31:23 | access to local variable s | null | | Assert.cs:32:27:32:27 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | | Assert.cs:32:27:32:27 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | +| Assert.cs:37:16:37:32 | String s = ... | non-null | Assert.cs:37:16:37:16 | access to local variable s | non-null | +| Assert.cs:37:16:37:32 | String s = ... | null | Assert.cs:37:16:37:16 | access to local variable s | null | | Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | | Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | | Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null | | Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null | | Assert.cs:39:27:39:27 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | | Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | +| Assert.cs:44:16:44:32 | String s = ... | non-null | Assert.cs:44:16:44:16 | access to local variable s | non-null | +| Assert.cs:44:16:44:32 | String s = ... | null | Assert.cs:44:16:44:16 | access to local variable s | null | | Assert.cs:45:24:45:24 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | | Assert.cs:45:24:45:24 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | | Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:45:24:45:24 | access to local variable s | null | | Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:45:24:45:24 | access to local variable s | non-null | | Assert.cs:46:27:46:27 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | | Assert.cs:46:27:46:27 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | +| Assert.cs:51:16:51:32 | String s = ... | non-null | Assert.cs:51:16:51:16 | access to local variable s | non-null | +| Assert.cs:51:16:51:32 | String s = ... | null | Assert.cs:51:16:51:16 | access to local variable s | null | | Assert.cs:52:24:52:24 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | | Assert.cs:52:24:52:24 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | | Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:52:24:52:24 | access to local variable s | non-null | | Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:52:24:52:24 | access to local variable s | null | | Assert.cs:53:27:53:27 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | | Assert.cs:53:27:53:27 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | +| Assert.cs:58:16:58:32 | String s = ... | non-null | Assert.cs:58:16:58:16 | access to local variable s | non-null | +| Assert.cs:58:16:58:32 | String s = ... | null | Assert.cs:58:16:58:16 | access to local variable s | null | | Assert.cs:59:23:59:23 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | | Assert.cs:59:23:59:23 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null | | Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:59:23:59:23 | access to local variable s | null | @@ -44,6 +60,8 @@ | Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:36:59:36 | access to parameter b | true | | Assert.cs:60:27:60:27 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | | Assert.cs:60:27:60:27 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null | +| Assert.cs:65:16:65:32 | String s = ... | non-null | Assert.cs:65:16:65:16 | access to local variable s | non-null | +| Assert.cs:65:16:65:32 | String s = ... | null | Assert.cs:65:16:65:16 | access to local variable s | null | | Assert.cs:66:24:66:24 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | | Assert.cs:66:24:66:24 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null | | Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:66:24:66:24 | access to local variable s | non-null | @@ -52,6 +70,8 @@ | Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:37:66:37 | access to parameter b | false | | Assert.cs:67:27:67:27 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | | Assert.cs:67:27:67:27 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null | +| Assert.cs:72:16:72:32 | String s = ... | non-null | Assert.cs:72:16:72:16 | access to local variable s | non-null | +| Assert.cs:72:16:72:32 | String s = ... | null | Assert.cs:72:16:72:16 | access to local variable s | null | | Assert.cs:73:23:73:23 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | | Assert.cs:73:23:73:23 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null | | Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:73:23:73:23 | access to local variable s | non-null | @@ -60,6 +80,8 @@ | Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:36:73:36 | access to parameter b | true | | Assert.cs:74:27:74:27 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | | Assert.cs:74:27:74:27 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null | +| Assert.cs:79:16:79:32 | String s = ... | non-null | Assert.cs:79:16:79:16 | access to local variable s | non-null | +| Assert.cs:79:16:79:32 | String s = ... | null | Assert.cs:79:16:79:16 | access to local variable s | null | | Assert.cs:80:24:80:24 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | | Assert.cs:80:24:80:24 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null | | Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:80:24:80:24 | access to local variable s | null | @@ -85,12 +107,16 @@ | Guards.cs:32:40:32:51 | !... | true | Guards.cs:32:42:32:50 | ... == ... | false | | Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:42:32:42 | access to parameter y | non-null | | Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:42:32:42 | access to parameter y | null | +| Guards.cs:33:31:33:35 | ... + ... | non-null | Guards.cs:33:31:33:31 | access to parameter x | non-null | +| Guards.cs:33:31:33:35 | ... + ... | non-null | Guards.cs:33:35:33:35 | access to parameter y | non-null | | Guards.cs:35:13:35:21 | ... == ... | false | Guards.cs:35:13:35:13 | access to parameter x | non-null | | Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:13 | access to parameter x | null | | Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:13:35:21 | ... == ... | false | | Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:26:35:34 | ... == ... | false | | Guards.cs:35:26:35:34 | ... == ... | false | Guards.cs:35:26:35:26 | access to parameter y | non-null | | Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:26:35:26 | access to parameter y | null | +| Guards.cs:36:32:36:36 | ... + ... | non-null | Guards.cs:36:32:36:32 | access to parameter x | non-null | +| Guards.cs:36:32:36:36 | ... + ... | non-null | Guards.cs:36:36:36:36 | access to parameter y | non-null | | Guards.cs:38:13:38:37 | !... | false | Guards.cs:38:15:38:36 | ... \|\| ... | true | | Guards.cs:38:13:38:37 | !... | true | Guards.cs:38:15:38:36 | ... \|\| ... | false | | Guards.cs:38:15:38:23 | ... == ... | false | Guards.cs:38:15:38:15 | access to parameter x | non-null | @@ -99,6 +125,8 @@ | Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:28:38:36 | ... == ... | false | | Guards.cs:38:28:38:36 | ... == ... | false | Guards.cs:38:28:38:28 | access to parameter y | non-null | | Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:28:38:28 | access to parameter y | null | +| Guards.cs:39:31:39:35 | ... + ... | non-null | Guards.cs:39:31:39:31 | access to parameter x | non-null | +| Guards.cs:39:31:39:35 | ... + ... | non-null | Guards.cs:39:35:39:35 | access to parameter y | non-null | | Guards.cs:41:13:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true | | Guards.cs:41:13:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false | | Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:15:41:39 | !... | true | @@ -111,6 +139,8 @@ | Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:30:41:38 | ... != ... | true | | Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:30:41:30 | access to parameter y | null | | Guards.cs:41:30:41:38 | ... != ... | true | Guards.cs:41:30:41:30 | access to parameter y | non-null | +| Guards.cs:42:32:42:36 | ... + ... | non-null | Guards.cs:42:32:42:32 | access to parameter x | non-null | +| Guards.cs:42:32:42:36 | ... + ... | non-null | Guards.cs:42:36:42:36 | access to parameter y | non-null | | Guards.cs:44:13:44:25 | ... != ... | false | Guards.cs:44:13:44:17 | access to field Field | null | | Guards.cs:44:13:44:25 | ... != ... | true | Guards.cs:44:13:44:17 | access to field Field | non-null | | Guards.cs:47:13:47:25 | ... != ... | false | Guards.cs:47:13:47:17 | access to field Field | null | @@ -121,6 +151,10 @@ | Guards.cs:60:13:60:45 | ... == ... | true | Guards.cs:60:13:60:37 | access to field Field | null | | Guards.cs:68:16:68:24 | ... != ... | false | Guards.cs:68:16:68:16 | access to parameter s | null | | Guards.cs:68:16:68:24 | ... != ... | true | Guards.cs:68:16:68:16 | access to parameter s | non-null | +| Guards.cs:71:13:71:20 | ... = ... | non-null | Guards.cs:71:13:71:13 | access to parameter s | non-null | +| Guards.cs:71:13:71:20 | ... = ... | non-null | Guards.cs:71:17:71:20 | null | non-null | +| Guards.cs:71:13:71:20 | ... = ... | null | Guards.cs:71:13:71:13 | access to parameter s | null | +| Guards.cs:71:13:71:20 | ... = ... | null | Guards.cs:71:17:71:20 | null | null | | Guards.cs:72:31:72:31 | access to parameter s | non-null | Guards.cs:71:17:71:20 | null | non-null | | Guards.cs:72:31:72:31 | access to parameter s | null | Guards.cs:71:17:71:20 | null | null | | Guards.cs:78:13:78:26 | ... == ... | true | Guards.cs:78:15:78:21 | access to property Length | non-null | @@ -143,6 +177,7 @@ | Guards.cs:88:15:88:21 | access to property Length | non-null | Guards.cs:88:13:88:13 | access to parameter s | non-null | | Guards.cs:88:15:88:21 | access to property Length | null | Guards.cs:88:13:88:13 | access to parameter s | null | | Guards.cs:92:13:92:25 | ... - ... | non-null | Guards.cs:92:15:92:21 | access to property Length | non-null | +| Guards.cs:92:13:92:25 | ... - ... | non-null | Guards.cs:92:25:92:25 | (...) ... | non-null | | Guards.cs:92:13:92:25 | ... - ... | null | Guards.cs:92:15:92:21 | access to property Length | null | | Guards.cs:92:13:92:30 | ... != ... | false | Guards.cs:92:13:92:25 | ... - ... | non-null | | Guards.cs:92:15:92:21 | access to property Length | non-null | Guards.cs:92:13:92:13 | access to parameter s | non-null | @@ -150,10 +185,29 @@ | Guards.cs:96:13:96:19 | ... == ... | true | Guards.cs:96:13:96:13 | access to parameter s | non-null | | Guards.cs:104:13:104:45 | ... == ... | false | Guards.cs:104:13:104:37 | access to field Field | non-null | | Guards.cs:104:13:104:45 | ... == ... | true | Guards.cs:104:13:104:37 | access to field Field | null | +| Guards.cs:106:9:106:25 | ... = ... | non-null | Guards.cs:106:9:106:18 | access to property Property | non-null | +| Guards.cs:106:9:106:25 | ... = ... | non-null | Guards.cs:106:22:106:25 | null | non-null | +| Guards.cs:106:9:106:25 | ... = ... | null | Guards.cs:106:9:106:18 | access to property Property | null | +| Guards.cs:106:9:106:25 | ... = ... | null | Guards.cs:106:22:106:25 | null | null | +| Guards.cs:113:13:114:38 | String dummy = ... | non-null | Guards.cs:113:13:113:17 | access to local variable dummy | non-null | +| Guards.cs:113:13:114:38 | String dummy = ... | null | Guards.cs:113:13:113:17 | access to local variable dummy | null | +| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:9:115:13 | access to local variable dummy | non-null | +| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:17:115:55 | ... ?? ... | non-null | +| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:9:115:13 | access to local variable dummy | null | +| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:17:115:55 | ... ?? ... | null | +| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:9:117:18 | access to property Property | non-null | +| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:22:117:25 | null | non-null | +| Guards.cs:117:9:117:25 | ... = ... | null | Guards.cs:117:9:117:18 | access to property Property | null | +| Guards.cs:117:9:117:25 | ... = ... | null | Guards.cs:117:22:117:25 | null | null | +| Guards.cs:124:13:124:30 | Boolean b1 = ... | false | Guards.cs:124:13:124:14 | access to local variable b1 | false | +| Guards.cs:124:13:124:30 | Boolean b1 = ... | true | Guards.cs:124:13:124:14 | access to local variable b1 | true | +| Guards.cs:125:13:125:31 | Nullable b2 = ... | non-null | Guards.cs:125:13:125:14 | access to local variable b2 | non-null | +| Guards.cs:125:13:125:31 | Nullable b2 = ... | null | Guards.cs:125:13:125:14 | access to local variable b2 | null | | Guards.cs:125:21:125:31 | call to method Equals | non-null | Guards.cs:125:18:125:19 | access to parameter s1 | non-null | | Guards.cs:125:21:125:31 | call to method Equals | null | Guards.cs:125:18:125:19 | access to parameter s1 | null | | Guards.cs:130:13:130:21 | ... is ... | false | Guards.cs:130:13:130:13 | access to parameter s | non-null | | Guards.cs:130:13:130:21 | ... is ... | true | Guards.cs:130:13:130:13 | access to parameter s | null | +| Guards.cs:137:13:137:23 | ... is ... | false | Guards.cs:137:13:137:13 | access to parameter s | null | | Guards.cs:137:13:137:23 | ... is ... | true | Guards.cs:137:13:137:13 | access to parameter s | non-null | | Guards.cs:144:13:144:25 | ... is ... | true | Guards.cs:144:13:144:13 | access to parameter o | non-null | | Guards.cs:145:20:145:20 | access to local variable s | non-null | Guards.cs:144:13:144:13 | access to parameter o | non-null | @@ -224,7 +278,13 @@ | Splitting.cs:105:22:105:30 | ... != ... | true | Splitting.cs:105:22:105:22 | access to parameter o | non-null | | Splitting.cs:116:22:116:30 | ... != ... | false | Splitting.cs:116:22:116:22 | access to parameter o | null | | Splitting.cs:116:22:116:30 | ... != ... | true | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:125:16:125:23 | Object o = ... | non-null | Splitting.cs:125:16:125:16 | access to local variable o | non-null | +| Splitting.cs:125:16:125:23 | Object o = ... | null | Splitting.cs:125:16:125:16 | access to local variable o | null | | Splitting.cs:128:17:128:25 | ... != ... | false | Splitting.cs:128:17:128:17 | access to local variable o | null | | Splitting.cs:128:17:128:25 | ... != ... | true | Splitting.cs:128:17:128:17 | access to local variable o | non-null | +| Splitting.cs:132:17:132:29 | ... = ... | non-null | Splitting.cs:132:17:132:17 | access to local variable o | non-null | +| Splitting.cs:132:17:132:29 | ... = ... | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null | +| Splitting.cs:132:17:132:29 | ... = ... | null | Splitting.cs:132:17:132:17 | access to local variable o | null | +| Splitting.cs:132:17:132:29 | ... = ... | null | Splitting.cs:132:21:132:29 | call to method M11 | null | | Splitting.cs:133:17:133:17 | access to local variable o | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null | | Splitting.cs:133:17:133:17 | access to local variable o | null | Splitting.cs:132:21:132:29 | call to method M11 | null | diff --git a/csharp/ql/test/query-tests/Nullness/A.cs b/csharp/ql/test/query-tests/Nullness/A.cs index 62395386aea..51bbc280e3c 100644 --- a/csharp/ql/test/query-tests/Nullness/A.cs +++ b/csharp/ql/test/query-tests/Nullness/A.cs @@ -47,7 +47,7 @@ class A object varRef = null; TestMethod2(ref varRef); - varRef.ToString(); // BAD (always) (false negative) + varRef.ToString(); // BAD (always) varRef = null; TestMethod3(ref varRef); diff --git a/csharp/ql/test/query-tests/Nullness/C.cs b/csharp/ql/test/query-tests/Nullness/C.cs index 0260ec10273..eeed247d222 100644 --- a/csharp/ql/test/query-tests/Nullness/C.cs +++ b/csharp/ql/test/query-tests/Nullness/C.cs @@ -101,7 +101,7 @@ public class C { if (Maybe()) list = null; - foreach (var x in list) // BAD (maybe) (false negative) + foreach (var x in list) // BAD (maybe) { x.ToString(); // GOOD list.ToString(); // GOOD @@ -168,7 +168,7 @@ public class C s = null; do { - s.ToString(); // BAD (always) (reported as maybe) + s.ToString(); // BAD (always) } while (s != null); diff --git a/csharp/ql/test/query-tests/Nullness/D.cs b/csharp/ql/test/query-tests/Nullness/D.cs index 55ac9de6ab5..83feebd3766 100644 --- a/csharp/ql/test/query-tests/Nullness/D.cs +++ b/csharp/ql/test/query-tests/Nullness/D.cs @@ -20,7 +20,7 @@ public class D public void Callee1(object param) { - param.ToString(); // BAD (maybe) (false negative) + param.ToString(); // BAD (maybe) } public void Callee2(object param) @@ -29,7 +29,7 @@ public class D { param.ToString(); // GOOD } - param.ToString(); // BAD (maybe) (false negative) + param.ToString(); // BAD (maybe) } private static bool CustomIsNull(object x) @@ -99,7 +99,7 @@ public class D } if (i > 4) - foreach (var _ in xs) ; // BAD (maybe) (false negative) + foreach (var _ in xs) ; // BAD (maybe) if (i > 5) lock (xs) // BAD (maybe) @@ -117,7 +117,7 @@ public class D var x = b ? null : "abc"; x = x == null ? "" : x; if (x == null) - x.ToString(); // BAD (always) (false negative) + x.ToString(); // BAD (always) else x.ToString(); // GOOD } @@ -131,8 +131,8 @@ public class D { for (int i = 0; i < alen; i++) { - sum += a[i]; // GOOD - sum += b[i]; // GOOD + sum += a[i]; // GOOD (false positive) + sum += b[i]; // GOOD (false positive) } } int alen2; @@ -142,13 +142,13 @@ public class D alen2 = 0; for (int i = 1; i <= alen2; ++i) { - sum += a[i - 1]; // GOOD + sum += a[i - 1]; // GOOD (false positive) } } public void MissedGuard(object obj) { - obj.ToString(); // BAD (maybe) (false negative) + obj.ToString(); // BAD (maybe) var x = obj != null ? 1 : 0; } @@ -194,7 +194,7 @@ public class D { var o = new Object(); if (o == null) - o.ToString(); // BAD (always) (false negative) + o.ToString(); // BAD (always) o.ToString(); // GOOD try @@ -204,7 +204,7 @@ public class D catch (Exception e) { if (e == null) - e.ToString(); // BAD (always) (false negative) + e.ToString(); // BAD (always) e.ToString(); // GOOD } @@ -214,12 +214,12 @@ public class D var o3 = "abc"; if (o3 == null) - o3.ToString(); // BAD (always) (false negative) + o3.ToString(); // BAD (always) o3.ToString(); // GOOD var o4 = "" + null; if (o4 == null) - o4.ToString(); // BAD (always) (false negative) + o4.ToString(); // BAD (always) o4.ToString(); // GOOD } @@ -343,7 +343,7 @@ public class D msg += "foobar"; throw new Exception(msg); } - obj.ToString(); // GOOD + obj.ToString(); // GOOD (false positive) } public void LoopCorr(int iters) @@ -392,12 +392,12 @@ public class D int i; for (i = 0; i < alen; i++) { - sum += a[i]; // GOOD + sum += a[i]; // GOOD (false positive) } int blen = b == null ? 0 : b.Length; // GOOD for (i = 0; i < blen; i++) { - sum += b[i]; // GOOD + sum += b[i]; // GOOD (false positive) } i = -3; } @@ -407,8 +407,8 @@ public class D if ((x != null && y == null) || (x == null && y != null)) return; if (x != null) - y.ToString(); // GOOD + y.ToString(); // GOOD (false positive) if (y != null) - x.ToString(); // GOOD + x.ToString(); // GOOD (false positive) } } diff --git a/csharp/ql/test/query-tests/Nullness/E.cs b/csharp/ql/test/query-tests/Nullness/E.cs index 9c2a1560ad9..6ab527d8c90 100644 --- a/csharp/ql/test/query-tests/Nullness/E.cs +++ b/csharp/ql/test/query-tests/Nullness/E.cs @@ -70,7 +70,7 @@ public class E arrLen = arr == null ? 0 : arr.Length; if (arrLen > 0) - arr[0] = 0; // GOOD + arr[0] = 0; // GOOD (false positive) } public const int MY_CONST_A = 1; @@ -90,12 +90,12 @@ public class E switch (switchguard) { case MY_CONST_A: - vals[0] = 0; // GOOD + vals[0] = 0; // GOOD (false positive) break; case MY_CONST_C: break; case MY_CONST_B: - vals[0] = 0; // GOOD + vals[0] = 0; // GOOD (false positive) break; default: throw new Exception(); @@ -156,7 +156,7 @@ public class E cond = true; } if (cond) - obj2.ToString(); // GOOD + obj2.ToString(); // GOOD (false positive) } public void Ex10(int[] a) @@ -164,7 +164,7 @@ public class E int n = a == null ? 0 : a.Length; for (var i = 0; i < n; i++) { - int x = a[i]; // GOOD + int x = a[i]; // GOOD (false positive) if (x > 7) a = new int[n]; } @@ -175,7 +175,7 @@ public class E bool b2 = obj == null ? false : b1; if (b2 == null) { - obj.ToString(); // GOOD + obj.ToString(); // GOOD (false positive) } if (obj == null) { @@ -183,13 +183,13 @@ public class E } if (b1 == null) { - obj.ToString(); // GOOD + obj.ToString(); // GOOD (false positive) } } public void Ex12(object o) { - var i = o.GetHashCode(); // BAD (maybe) (false negative) + var i = o.GetHashCode(); // BAD (maybe) var s = o?.ToString(); } @@ -198,16 +198,16 @@ public class E var o = b ? null : ""; o.M1(); // GOOD if (b) - o.M2(); // BAD (maybe) (false negative) + o.M2(); // BAD (maybe) else - o.Select(x => x); // BAD (maybe) (false negative) + o.Select(x => x); // BAD (maybe) } public int Ex14(string s) { if (s is string) return s.Length; - return s.GetHashCode(); // BAD (always) (false negative) + return s.GetHashCode(); // BAD (always) } public void Ex15(bool b) @@ -217,7 +217,7 @@ public class E x = null; x.ToString(); // BAD (maybe) if (b) - x.ToString(); // BAD (always) (false negative) + x.ToString(); // BAD (always) } public void Ex16(bool b) @@ -227,17 +227,17 @@ public class E x = null; if (b) x.ToString(); // BAD (always) - x.ToString(); // BAD (maybe) (false negative) + x.ToString(); // BAD (maybe) } public int Ex17(int? i) { - return i.Value; // BAD (maybe) (false negative) + return i.Value; // BAD (maybe) } public int Ex18(int? i) { - return (int)i; // BAD (maybe) (false negative) + return (int)i; // BAD (maybe) } public int Ex19(int? i) diff --git a/csharp/ql/test/query-tests/Nullness/Forwarding.cs b/csharp/ql/test/query-tests/Nullness/Forwarding.cs index ae820066489..fc7b69da490 100644 --- a/csharp/ql/test/query-tests/Nullness/Forwarding.cs +++ b/csharp/ql/test/query-tests/Nullness/Forwarding.cs @@ -33,7 +33,7 @@ class ForwardingTests if (IsNotNullWrong(s)) { - Console.WriteLine(s.Length); // BAD (always) (reported as maybe) + Console.WriteLine(s.Length); // BAD (always) } AssertIsNotNull(s); diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index d8c0e36fa2e..ded9f04a903 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -1,15 +1,33 @@ +| A.cs:7:16:7:40 | Object synchronizedAlways = ... | non-null | A.cs:7:16:7:33 | access to local variable synchronizedAlways | non-null | +| A.cs:7:16:7:40 | Object synchronizedAlways = ... | null | A.cs:7:16:7:33 | access to local variable synchronizedAlways | null | | A.cs:8:15:8:32 | access to local variable synchronizedAlways | non-null | A.cs:7:37:7:40 | null | non-null | | A.cs:8:15:8:32 | access to local variable synchronizedAlways | null | A.cs:7:37:7:40 | null | null | | A.cs:10:13:10:30 | access to local variable synchronizedAlways | non-null | A.cs:7:37:7:40 | null | non-null | | A.cs:10:13:10:30 | access to local variable synchronizedAlways | null | A.cs:7:37:7:40 | null | null | +| A.cs:16:15:16:30 | Int32[] arrayNull = ... | non-null | A.cs:16:15:16:23 | access to local variable arrayNull | non-null | +| A.cs:16:15:16:30 | Int32[] arrayNull = ... | null | A.cs:16:15:16:23 | access to local variable arrayNull | null | | A.cs:17:9:17:17 | access to local variable arrayNull | non-null | A.cs:16:27:16:30 | null | non-null | | A.cs:17:9:17:17 | access to local variable arrayNull | null | A.cs:16:27:16:30 | null | null | +| A.cs:20:9:20:29 | ... = ... | non-null | A.cs:20:9:20:15 | access to local variable arrayOk | non-null | +| A.cs:20:9:20:29 | ... = ... | non-null | A.cs:20:19:20:29 | array creation of type Int32[] | non-null | +| A.cs:20:9:20:29 | ... = ... | null | A.cs:20:9:20:15 | access to local variable arrayOk | null | +| A.cs:20:9:20:29 | ... = ... | null | A.cs:20:19:20:29 | array creation of type Int32[] | null | | A.cs:21:9:21:15 | access to local variable arrayOk | non-null | A.cs:20:19:20:29 | array creation of type Int32[] | non-null | | A.cs:21:9:21:15 | access to local variable arrayOk | null | A.cs:20:19:20:29 | array creation of type Int32[] | null | +| A.cs:26:15:26:32 | Int32[] arrayAccess = ... | non-null | A.cs:26:15:26:25 | access to local variable arrayAccess | non-null | +| A.cs:26:15:26:32 | Int32[] arrayAccess = ... | null | A.cs:26:15:26:25 | access to local variable arrayAccess | null | +| A.cs:27:18:27:35 | String[] fieldAccess = ... | non-null | A.cs:27:18:27:28 | access to local variable fieldAccess | non-null | +| A.cs:27:18:27:35 | String[] fieldAccess = ... | null | A.cs:27:18:27:28 | access to local variable fieldAccess | null | +| A.cs:28:16:28:34 | Object methodAccess = ... | non-null | A.cs:28:16:28:27 | access to local variable methodAccess | non-null | +| A.cs:28:16:28:34 | Object methodAccess = ... | null | A.cs:28:16:28:27 | access to local variable methodAccess | null | +| A.cs:29:16:29:32 | Object methodCall = ... | non-null | A.cs:29:16:29:25 | access to local variable methodCall | non-null | +| A.cs:29:16:29:32 | Object methodCall = ... | null | A.cs:29:16:29:25 | access to local variable methodCall | null | | A.cs:31:27:31:37 | access to local variable arrayAccess | non-null | A.cs:26:29:26:32 | null | non-null | | A.cs:31:27:31:37 | access to local variable arrayAccess | null | A.cs:26:29:26:32 | null | null | | A.cs:32:27:32:37 | access to local variable fieldAccess | non-null | A.cs:27:32:27:35 | null | non-null | | A.cs:32:27:32:37 | access to local variable fieldAccess | null | A.cs:27:32:27:35 | null | null | +| A.cs:33:22:33:48 | Func tmp = ... | non-null | A.cs:33:22:33:24 | access to local variable tmp | non-null | +| A.cs:33:22:33:48 | Func tmp = ... | null | A.cs:33:22:33:24 | access to local variable tmp | null | | A.cs:33:28:33:39 | access to local variable methodAccess | non-null | A.cs:28:31:28:34 | null | non-null | | A.cs:33:28:33:39 | access to local variable methodAccess | null | A.cs:28:31:28:34 | null | null | | A.cs:34:27:34:36 | access to local variable methodCall | non-null | A.cs:29:29:29:32 | null | non-null | @@ -18,56 +36,114 @@ | A.cs:36:27:36:37 | access to local variable arrayAccess | null | A.cs:26:29:26:32 | null | null | | A.cs:37:27:37:37 | access to local variable fieldAccess | non-null | A.cs:27:32:27:35 | null | non-null | | A.cs:37:27:37:37 | access to local variable fieldAccess | null | A.cs:27:32:27:35 | null | null | +| A.cs:38:9:38:35 | ... = ... | non-null | A.cs:38:9:38:11 | access to local variable tmp | non-null | +| A.cs:38:9:38:35 | ... = ... | non-null | A.cs:38:15:38:35 | delegate creation of type Func | non-null | +| A.cs:38:9:38:35 | ... = ... | null | A.cs:38:9:38:11 | access to local variable tmp | null | +| A.cs:38:9:38:35 | ... = ... | null | A.cs:38:15:38:35 | delegate creation of type Func | null | | A.cs:38:15:38:26 | access to local variable methodAccess | non-null | A.cs:28:31:28:34 | null | non-null | | A.cs:38:15:38:26 | access to local variable methodAccess | null | A.cs:28:31:28:34 | null | null | | A.cs:39:27:39:36 | access to local variable methodCall | non-null | A.cs:29:29:29:32 | null | non-null | | A.cs:39:27:39:36 | access to local variable methodCall | null | A.cs:29:29:29:32 | null | null | +| A.cs:44:16:44:28 | Object varOut = ... | non-null | A.cs:44:16:44:21 | access to local variable varOut | non-null | +| A.cs:44:16:44:28 | Object varOut = ... | null | A.cs:44:16:44:21 | access to local variable varOut | null | +| A.cs:48:16:48:28 | Object varRef = ... | non-null | A.cs:48:16:48:21 | access to local variable varRef | non-null | +| A.cs:48:16:48:28 | Object varRef = ... | null | A.cs:48:16:48:21 | access to local variable varRef | null | | A.cs:49:25:49:30 | access to local variable varRef | non-null | A.cs:48:25:48:28 | null | non-null | | A.cs:49:25:49:30 | access to local variable varRef | null | A.cs:48:25:48:28 | null | null | | A.cs:50:9:50:14 | access to local variable varRef | non-null | A.cs:48:25:48:28 | null | non-null | | A.cs:50:9:50:14 | access to local variable varRef | null | A.cs:48:25:48:28 | null | null | +| A.cs:52:9:52:21 | ... = ... | non-null | A.cs:52:9:52:14 | access to local variable varRef | non-null | +| A.cs:52:9:52:21 | ... = ... | non-null | A.cs:52:18:52:21 | null | non-null | +| A.cs:52:9:52:21 | ... = ... | null | A.cs:52:9:52:14 | access to local variable varRef | null | +| A.cs:52:9:52:21 | ... = ... | null | A.cs:52:18:52:21 | null | null | | A.cs:53:25:53:30 | access to local variable varRef | non-null | A.cs:52:18:52:21 | null | non-null | | A.cs:53:25:53:30 | access to local variable varRef | null | A.cs:52:18:52:21 | null | null | +| A.cs:59:16:59:28 | String actual = ... | non-null | A.cs:59:16:59:21 | access to local variable actual | non-null | +| A.cs:59:16:59:28 | String actual = ... | null | A.cs:59:16:59:21 | access to local variable actual | null | +| A.cs:61:20:61:45 | MyDelegate fun = ... | non-null | A.cs:61:20:61:22 | access to local variable fun | non-null | +| A.cs:61:20:61:45 | MyDelegate fun = ... | null | A.cs:61:20:61:22 | access to local variable fun | null | +| A.cs:61:36:61:45 | ... = ... | non-null | A.cs:61:36:61:41 | access to local variable actual | non-null | +| A.cs:61:36:61:45 | ... = ... | non-null | A.cs:61:45:61:45 | access to parameter e | non-null | +| A.cs:61:36:61:45 | ... = ... | null | A.cs:61:36:61:41 | access to local variable actual | null | +| A.cs:61:36:61:45 | ... = ... | null | A.cs:61:45:61:45 | access to parameter e | null | | A.cs:63:9:63:11 | access to local variable fun | non-null | A.cs:61:26:61:45 | (...) => ... | non-null | | A.cs:63:9:63:11 | access to local variable fun | null | A.cs:61:26:61:45 | (...) => ... | null | +| A.cs:69:9:69:16 | ... = ... | non-null | A.cs:69:9:69:11 | access to parameter num | non-null | +| A.cs:69:9:69:16 | ... = ... | non-null | A.cs:69:15:69:16 | (...) ... | non-null | +| A.cs:69:9:69:16 | ... = ... | null | A.cs:69:9:69:11 | access to parameter num | null | +| A.cs:69:9:69:16 | ... = ... | null | A.cs:69:15:69:16 | (...) ... | null | +| A.cs:78:9:78:16 | ... = ... | non-null | A.cs:78:9:78:11 | access to parameter num | non-null | +| A.cs:78:9:78:16 | ... = ... | non-null | A.cs:78:15:78:16 | (...) ... | non-null | +| A.cs:78:9:78:16 | ... = ... | null | A.cs:78:9:78:11 | access to parameter num | null | +| A.cs:78:9:78:16 | ... = ... | null | A.cs:78:15:78:16 | (...) ... | null | +| Assert.cs:9:16:9:32 | String s = ... | non-null | Assert.cs:9:16:9:16 | access to local variable s | non-null | +| Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null | | Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | | Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null | | Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null | | Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | +| Assert.cs:13:9:13:25 | ... = ... | non-null | Assert.cs:13:9:13:9 | access to local variable s | non-null | +| Assert.cs:13:9:13:25 | ... = ... | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | +| Assert.cs:13:9:13:25 | ... = ... | null | Assert.cs:13:9:13:9 | access to local variable s | null | +| Assert.cs:13:9:13:25 | ... = ... | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | | Assert.cs:14:23:14:23 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | | Assert.cs:14:23:14:23 | access to local variable s | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | | Assert.cs:15:27:15:27 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | | Assert.cs:15:27:15:27 | access to local variable s | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | +| Assert.cs:17:9:17:25 | ... = ... | non-null | Assert.cs:17:9:17:9 | access to local variable s | non-null | +| Assert.cs:17:9:17:25 | ... = ... | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | +| Assert.cs:17:9:17:25 | ... = ... | null | Assert.cs:17:9:17:9 | access to local variable s | null | +| Assert.cs:17:9:17:25 | ... = ... | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | | Assert.cs:18:26:18:26 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | | Assert.cs:18:26:18:26 | access to local variable s | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | | Assert.cs:19:27:19:27 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | | Assert.cs:19:27:19:27 | access to local variable s | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | +| Assert.cs:21:9:21:25 | ... = ... | non-null | Assert.cs:21:9:21:9 | access to local variable s | non-null | +| Assert.cs:21:9:21:25 | ... = ... | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | +| Assert.cs:21:9:21:25 | ... = ... | null | Assert.cs:21:9:21:9 | access to local variable s | null | +| Assert.cs:21:9:21:25 | ... = ... | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | | Assert.cs:22:23:22:23 | access to local variable s | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | | Assert.cs:22:23:22:23 | access to local variable s | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | | Assert.cs:22:23:22:31 | ... == ... | false | Assert.cs:22:23:22:23 | access to local variable s | non-null | | Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:22:23:22:23 | access to local variable s | null | | Assert.cs:23:27:23:27 | access to local variable s | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | | Assert.cs:23:27:23:27 | access to local variable s | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | +| Assert.cs:25:9:25:25 | ... = ... | non-null | Assert.cs:25:9:25:9 | access to local variable s | non-null | +| Assert.cs:25:9:25:25 | ... = ... | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | +| Assert.cs:25:9:25:25 | ... = ... | null | Assert.cs:25:9:25:9 | access to local variable s | null | +| Assert.cs:25:9:25:25 | ... = ... | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | | Assert.cs:26:23:26:23 | access to local variable s | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | | Assert.cs:26:23:26:23 | access to local variable s | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | | Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:26:23:26:23 | access to local variable s | null | | Assert.cs:26:23:26:31 | ... != ... | true | Assert.cs:26:23:26:23 | access to local variable s | non-null | | Assert.cs:27:27:27:27 | access to local variable s | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | | Assert.cs:27:27:27:27 | access to local variable s | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | +| Assert.cs:29:9:29:25 | ... = ... | non-null | Assert.cs:29:9:29:9 | access to local variable s | non-null | +| Assert.cs:29:9:29:25 | ... = ... | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | +| Assert.cs:29:9:29:25 | ... = ... | null | Assert.cs:29:9:29:9 | access to local variable s | null | +| Assert.cs:29:9:29:25 | ... = ... | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | | Assert.cs:30:24:30:24 | access to local variable s | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | | Assert.cs:30:24:30:24 | access to local variable s | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | | Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:30:24:30:24 | access to local variable s | null | | Assert.cs:30:24:30:32 | ... != ... | true | Assert.cs:30:24:30:24 | access to local variable s | non-null | | Assert.cs:31:27:31:27 | access to local variable s | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | | Assert.cs:31:27:31:27 | access to local variable s | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | +| Assert.cs:33:9:33:25 | ... = ... | non-null | Assert.cs:33:9:33:9 | access to local variable s | non-null | +| Assert.cs:33:9:33:25 | ... = ... | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | +| Assert.cs:33:9:33:25 | ... = ... | null | Assert.cs:33:9:33:9 | access to local variable s | null | +| Assert.cs:33:9:33:25 | ... = ... | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | | Assert.cs:34:24:34:24 | access to local variable s | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | | Assert.cs:34:24:34:24 | access to local variable s | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | | Assert.cs:34:24:34:32 | ... == ... | false | Assert.cs:34:24:34:24 | access to local variable s | non-null | | Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:34:24:34:24 | access to local variable s | null | | Assert.cs:35:27:35:27 | access to local variable s | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | | Assert.cs:35:27:35:27 | access to local variable s | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | +| Assert.cs:37:9:37:25 | ... = ... | non-null | Assert.cs:37:9:37:9 | access to local variable s | non-null | +| Assert.cs:37:9:37:25 | ... = ... | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | +| Assert.cs:37:9:37:25 | ... = ... | null | Assert.cs:37:9:37:9 | access to local variable s | null | +| Assert.cs:37:9:37:25 | ... = ... | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | | Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | | Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | | Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null | @@ -76,6 +152,10 @@ | Assert.cs:38:23:38:36 | ... && ... | true | Assert.cs:38:36:38:36 | access to parameter b | true | | Assert.cs:39:27:39:27 | access to local variable s | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | | Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | +| Assert.cs:41:9:41:25 | ... = ... | non-null | Assert.cs:41:9:41:9 | access to local variable s | non-null | +| Assert.cs:41:9:41:25 | ... = ... | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | +| Assert.cs:41:9:41:25 | ... = ... | null | Assert.cs:41:9:41:9 | access to local variable s | null | +| Assert.cs:41:9:41:25 | ... = ... | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | | Assert.cs:42:24:42:24 | access to local variable s | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | | Assert.cs:42:24:42:24 | access to local variable s | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | | Assert.cs:42:24:42:32 | ... == ... | false | Assert.cs:42:24:42:24 | access to local variable s | non-null | @@ -84,6 +164,10 @@ | Assert.cs:42:24:42:37 | ... \|\| ... | false | Assert.cs:42:37:42:37 | access to parameter b | false | | Assert.cs:43:27:43:27 | access to local variable s | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | | Assert.cs:43:27:43:27 | access to local variable s | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | +| Assert.cs:45:9:45:25 | ... = ... | non-null | Assert.cs:45:9:45:9 | access to local variable s | non-null | +| Assert.cs:45:9:45:25 | ... = ... | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | +| Assert.cs:45:9:45:25 | ... = ... | null | Assert.cs:45:9:45:9 | access to local variable s | null | +| Assert.cs:45:9:45:25 | ... = ... | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | | Assert.cs:46:23:46:23 | access to local variable s | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | | Assert.cs:46:23:46:23 | access to local variable s | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | | Assert.cs:46:23:46:31 | ... == ... | false | Assert.cs:46:23:46:23 | access to local variable s | non-null | @@ -92,6 +176,10 @@ | Assert.cs:46:23:46:36 | ... && ... | true | Assert.cs:46:36:46:36 | access to parameter b | true | | Assert.cs:47:27:47:27 | access to local variable s | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | | Assert.cs:47:27:47:27 | access to local variable s | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | +| Assert.cs:49:9:49:25 | ... = ... | non-null | Assert.cs:49:9:49:9 | access to local variable s | non-null | +| Assert.cs:49:9:49:25 | ... = ... | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | +| Assert.cs:49:9:49:25 | ... = ... | null | Assert.cs:49:9:49:9 | access to local variable s | null | +| Assert.cs:49:9:49:25 | ... = ... | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | | Assert.cs:50:24:50:24 | access to local variable s | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | | Assert.cs:50:24:50:24 | access to local variable s | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | | Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:24:50:24 | access to local variable s | null | @@ -100,6 +188,14 @@ | Assert.cs:50:24:50:37 | ... \|\| ... | false | Assert.cs:50:37:50:37 | access to parameter b | false | | Assert.cs:51:27:51:27 | access to local variable s | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | | Assert.cs:51:27:51:27 | access to local variable s | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | +| B.cs:7:11:7:29 | B eqCallAlways = ... | non-null | B.cs:7:11:7:22 | access to local variable eqCallAlways | non-null | +| B.cs:7:11:7:29 | B eqCallAlways = ... | null | B.cs:7:11:7:22 | access to local variable eqCallAlways | null | +| B.cs:8:11:8:19 | B b2 = ... | non-null | B.cs:8:11:8:12 | access to local variable b2 | non-null | +| B.cs:8:11:8:19 | B b2 = ... | null | B.cs:8:11:8:12 | access to local variable b2 | null | +| B.cs:9:11:9:19 | B b3 = ... | non-null | B.cs:9:11:9:12 | access to local variable b3 | non-null | +| B.cs:9:11:9:19 | B b3 = ... | null | B.cs:9:11:9:12 | access to local variable b3 | null | +| B.cs:10:11:10:30 | B neqCallAlways = ... | non-null | B.cs:10:11:10:23 | access to local variable neqCallAlways | non-null | +| B.cs:10:11:10:30 | B neqCallAlways = ... | null | B.cs:10:11:10:23 | access to local variable neqCallAlways | null | | B.cs:12:13:12:24 | access to local variable eqCallAlways | non-null | B.cs:7:26:7:29 | null | non-null | | B.cs:12:13:12:24 | access to local variable eqCallAlways | null | B.cs:7:26:7:29 | null | null | | B.cs:12:13:12:32 | call to operator == | false | B.cs:12:13:12:24 | access to local variable eqCallAlways | non-null | @@ -126,14 +222,28 @@ | B.cs:24:13:24:25 | access to local variable neqCallAlways | null | B.cs:10:27:10:30 | null | null | | B.cs:34:16:34:26 | !... | false | B.cs:34:18:34:25 | call to operator == | true | | B.cs:34:16:34:26 | !... | true | B.cs:34:18:34:25 | call to operator == | false | +| B.cs:52:20:52:27 | Object o = ... | non-null | B.cs:52:20:52:20 | access to local variable o | non-null | +| B.cs:52:20:52:27 | Object o = ... | null | B.cs:52:20:52:20 | access to local variable o | null | +| B.cs:53:17:53:25 | (...) ... | non-null | B.cs:53:25:53:25 | access to local variable o | non-null | +| B.cs:53:17:53:25 | (...) ... | null | B.cs:53:25:53:25 | access to local variable o | null | | B.cs:53:17:53:33 | ... != ... | false | B.cs:53:17:53:25 | (...) ... | null | | B.cs:53:17:53:33 | ... != ... | true | B.cs:53:17:53:25 | (...) ... | non-null | | B.cs:53:25:53:25 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | | B.cs:53:25:53:25 | access to local variable o | null | B.cs:52:24:52:27 | null | null | +| B.cs:55:21:55:36 | Boolean eq = ... | false | B.cs:55:21:55:22 | access to local variable eq | false | +| B.cs:55:21:55:36 | Boolean eq = ... | true | B.cs:55:21:55:22 | access to local variable eq | true | | B.cs:55:26:55:26 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | | B.cs:55:26:55:26 | access to local variable o | null | B.cs:52:24:52:27 | null | null | | B.cs:55:35:55:35 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | | B.cs:55:35:55:35 | access to local variable o | null | B.cs:52:24:52:27 | null | null | +| B.cs:72:17:72:26 | Foo foo = ... | non-null | B.cs:72:17:72:19 | access to local variable foo | non-null | +| B.cs:72:17:72:26 | Foo foo = ... | null | B.cs:72:17:72:19 | access to local variable foo | null | +| B.cs:73:32:73:46 | ... = ... | non-null | B.cs:73:32:73:34 | access to local variable foo | non-null | +| B.cs:73:32:73:46 | ... = ... | non-null | B.cs:73:38:73:46 | object creation of type Foo | non-null | +| B.cs:73:32:73:46 | ... = ... | null | B.cs:73:32:73:34 | access to local variable foo | null | +| B.cs:73:32:73:46 | ... = ... | null | B.cs:73:38:73:46 | object creation of type Foo | null | +| C.cs:10:16:10:23 | Object o = ... | non-null | C.cs:10:16:10:16 | access to local variable o | non-null | +| C.cs:10:16:10:23 | Object o = ... | null | C.cs:10:16:10:16 | access to local variable o | null | | C.cs:11:13:11:30 | !... | false | C.cs:11:15:11:29 | !... | true | | C.cs:11:13:11:30 | !... | true | C.cs:11:15:11:29 | !... | false | | C.cs:11:15:11:29 | !... | false | C.cs:11:17:11:28 | !... | true | @@ -162,38 +272,56 @@ | C.cs:30:40:30:48 | ... != ... | true | C.cs:30:40:30:40 | access to parameter o | non-null | | C.cs:34:13:34:21 | ... == ... | false | C.cs:34:13:34:13 | access to parameter o | non-null | | C.cs:34:13:34:21 | ... == ... | true | C.cs:34:13:34:13 | access to parameter o | null | +| C.cs:40:13:40:35 | String s = ... | non-null | C.cs:40:13:40:13 | access to local variable s | non-null | +| C.cs:40:13:40:35 | String s = ... | null | C.cs:40:13:40:13 | access to local variable s | null | | C.cs:41:22:41:22 | access to local variable s | non-null | C.cs:40:17:40:35 | ... ? ... : ... | non-null | | C.cs:41:22:41:22 | access to local variable s | null | C.cs:40:17:40:35 | ... ? ... : ... | null | | C.cs:41:22:41:30 | ... == ... | false | C.cs:41:22:41:22 | access to local variable s | non-null | | C.cs:41:22:41:30 | ... == ... | true | C.cs:41:22:41:22 | access to local variable s | null | | C.cs:42:9:42:9 | access to local variable s | non-null | C.cs:40:17:40:35 | ... ? ... : ... | non-null | | C.cs:42:9:42:9 | access to local variable s | null | C.cs:40:17:40:35 | ... ? ... : ... | null | +| C.cs:44:9:44:31 | ... = ... | non-null | C.cs:44:9:44:9 | access to local variable s | non-null | +| C.cs:44:9:44:31 | ... = ... | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | +| C.cs:44:9:44:31 | ... = ... | null | C.cs:44:9:44:9 | access to local variable s | null | +| C.cs:44:9:44:31 | ... = ... | null | C.cs:44:13:44:31 | ... ? ... : ... | null | | C.cs:45:22:45:22 | access to local variable s | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | | C.cs:45:22:45:22 | access to local variable s | null | C.cs:44:13:44:31 | ... ? ... : ... | null | | C.cs:45:22:45:30 | ... != ... | false | C.cs:45:22:45:22 | access to local variable s | null | | C.cs:45:22:45:30 | ... != ... | true | C.cs:45:22:45:22 | access to local variable s | non-null | | C.cs:46:9:46:9 | access to local variable s | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | | C.cs:46:9:46:9 | access to local variable s | null | C.cs:44:13:44:31 | ... ? ... : ... | null | +| C.cs:51:13:51:29 | Object o1 = ... | non-null | C.cs:51:13:51:14 | access to local variable o1 | non-null | +| C.cs:51:13:51:29 | Object o1 = ... | null | C.cs:51:13:51:14 | access to local variable o1 | null | | C.cs:52:20:52:21 | access to local variable o1 | non-null | C.cs:51:18:51:29 | object creation of type Object | non-null | | C.cs:52:20:52:21 | access to local variable o1 | null | C.cs:51:18:51:29 | object creation of type Object | null | | C.cs:53:9:53:10 | access to local variable o1 | non-null | C.cs:51:18:51:29 | object creation of type Object | non-null | | C.cs:53:9:53:10 | access to local variable o1 | null | C.cs:51:18:51:29 | object creation of type Object | null | +| C.cs:55:13:55:36 | String o2 = ... | non-null | C.cs:55:13:55:14 | access to local variable o2 | non-null | +| C.cs:55:13:55:36 | String o2 = ... | null | C.cs:55:13:55:14 | access to local variable o2 | null | | C.cs:56:23:56:24 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | | C.cs:56:23:56:24 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | | C.cs:57:9:57:10 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | | C.cs:57:9:57:10 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | +| C.cs:62:13:62:46 | Object o1 = ... | non-null | C.cs:62:13:62:14 | access to local variable o1 | non-null | +| C.cs:62:13:62:46 | Object o1 = ... | null | C.cs:62:13:62:14 | access to local variable o1 | null | | C.cs:63:23:63:24 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | | C.cs:63:23:63:24 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | | C.cs:64:9:64:10 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | | C.cs:64:9:64:10 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | +| C.cs:66:13:66:46 | Object o2 = ... | non-null | C.cs:66:13:66:14 | access to local variable o2 | non-null | +| C.cs:66:13:66:46 | Object o2 = ... | null | C.cs:66:13:66:14 | access to local variable o2 | null | | C.cs:67:23:67:24 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | | C.cs:67:23:67:24 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | | C.cs:68:9:68:10 | access to local variable o2 | non-null | C.cs:66:18:66:46 | ... ? ... : ... | non-null | | C.cs:68:9:68:10 | access to local variable o2 | null | C.cs:66:18:66:46 | ... ? ... : ... | null | +| C.cs:70:13:70:46 | Object o3 = ... | non-null | C.cs:70:13:70:14 | access to local variable o3 | non-null | +| C.cs:70:13:70:46 | Object o3 = ... | null | C.cs:70:13:70:14 | access to local variable o3 | null | | C.cs:71:26:71:27 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | | C.cs:71:26:71:27 | access to local variable o3 | null | C.cs:70:18:70:46 | ... ? ... : ... | null | | C.cs:72:9:72:10 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | | C.cs:72:9:72:10 | access to local variable o3 | null | C.cs:70:18:70:46 | ... ? ... : ... | null | +| C.cs:77:16:77:23 | Object o = ... | non-null | C.cs:77:16:77:16 | access to local variable o | non-null | +| C.cs:77:16:77:23 | Object o = ... | null | C.cs:77:16:77:16 | access to local variable o | null | | C.cs:78:13:78:24 | call to method IsNotNull | false | C.cs:78:23:78:23 | access to local variable o | null | | C.cs:78:13:78:24 | call to method IsNotNull | true | C.cs:78:23:78:23 | access to local variable o | non-null | | C.cs:78:23:78:23 | access to local variable o | non-null | C.cs:77:20:77:23 | null | non-null | @@ -208,15 +336,27 @@ | C.cs:82:21:82:21 | access to local variable o | null | C.cs:77:20:77:23 | null | null | | C.cs:83:13:83:13 | access to local variable o | non-null | C.cs:77:20:77:23 | null | non-null | | C.cs:83:13:83:13 | access to local variable o | null | C.cs:77:20:77:23 | null | null | +| C.cs:88:16:88:23 | Object o = ... | non-null | C.cs:88:16:88:16 | access to local variable o | non-null | +| C.cs:88:16:88:23 | Object o = ... | null | C.cs:88:16:88:16 | access to local variable o | null | | C.cs:89:13:89:13 | access to local variable o | non-null | C.cs:88:20:88:23 | null | non-null | | C.cs:89:13:89:13 | access to local variable o | null | C.cs:88:20:88:23 | null | null | | C.cs:89:13:89:23 | ... is ... | true | C.cs:89:13:89:13 | access to local variable o | non-null | | C.cs:90:13:90:13 | access to local variable o | non-null | C.cs:88:20:88:23 | null | non-null | | C.cs:90:13:90:13 | access to local variable o | null | C.cs:88:20:88:23 | null | null | +| C.cs:95:13:95:45 | Object o = ... | non-null | C.cs:95:13:95:13 | access to local variable o | non-null | +| C.cs:95:13:95:45 | Object o = ... | null | C.cs:95:13:95:13 | access to local variable o | null | | C.cs:96:15:96:15 | access to local variable o | non-null | C.cs:95:17:95:45 | ... ? ... : ... | non-null | | C.cs:96:15:96:15 | access to local variable o | null | C.cs:95:17:95:45 | ... ? ... : ... | null | | C.cs:97:13:97:13 | access to local variable o | non-null | C.cs:95:17:95:45 | ... ? ... : ... | non-null | | C.cs:97:13:97:13 | access to local variable o | null | C.cs:95:17:95:45 | ... ? ... : ... | null | +| C.cs:103:13:103:23 | ... = ... | non-null | C.cs:103:13:103:16 | access to parameter list | non-null | +| C.cs:103:13:103:23 | ... = ... | non-null | C.cs:103:20:103:23 | null | non-null | +| C.cs:103:13:103:23 | ... = ... | null | C.cs:103:13:103:16 | access to parameter list | null | +| C.cs:103:13:103:23 | ... = ... | null | C.cs:103:20:103:23 | null | null | +| C.cs:113:16:113:29 | String colours = ... | non-null | C.cs:113:16:113:22 | access to local variable colours | non-null | +| C.cs:113:16:113:29 | String colours = ... | null | C.cs:113:16:113:22 | access to local variable colours | null | +| C.cs:114:13:114:90 | String colour = ... | non-null | C.cs:114:13:114:18 | access to local variable colour | non-null | +| C.cs:114:13:114:90 | String colour = ... | null | C.cs:114:13:114:18 | access to local variable colour | null | | C.cs:114:22:114:28 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | | C.cs:114:22:114:28 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | | C.cs:114:22:114:36 | ... == ... | false | C.cs:114:22:114:28 | access to local variable colours | non-null | @@ -227,50 +367,144 @@ | C.cs:114:41:114:47 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | | C.cs:114:73:114:79 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | | C.cs:114:73:114:79 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | +| C.cs:119:18:119:32 | String[] children = ... | non-null | C.cs:119:18:119:25 | access to local variable children | non-null | +| C.cs:119:18:119:32 | String[] children = ... | null | C.cs:119:18:119:25 | access to local variable children | null | +| C.cs:120:13:120:27 | String comparator = ... | non-null | C.cs:120:13:120:22 | access to local variable comparator | non-null | +| C.cs:120:13:120:27 | String comparator = ... | null | C.cs:120:13:120:22 | access to local variable comparator | null | | C.cs:121:13:121:20 | access to local variable children | non-null | C.cs:119:29:119:32 | null | non-null | | C.cs:121:13:121:20 | access to local variable children | null | C.cs:119:29:119:32 | null | null | | C.cs:121:13:121:28 | ... == ... | false | C.cs:121:13:121:20 | access to local variable children | non-null | | C.cs:121:13:121:28 | ... == ... | true | C.cs:121:13:121:20 | access to local variable children | null | +| C.cs:122:13:122:36 | ... = ... | non-null | C.cs:122:13:122:20 | access to local variable children | non-null | +| C.cs:122:13:122:36 | ... = ... | non-null | C.cs:122:24:122:36 | array creation of type String[] | non-null | +| C.cs:122:13:122:36 | ... = ... | null | C.cs:122:13:122:20 | access to local variable children | null | +| C.cs:122:13:122:36 | ... = ... | null | C.cs:122:24:122:36 | array creation of type String[] | null | +| C.cs:129:16:129:24 | String ok = ... | non-null | C.cs:129:16:129:17 | access to local variable ok | non-null | +| C.cs:129:16:129:24 | String ok = ... | null | C.cs:129:16:129:17 | access to local variable ok | null | | C.cs:130:13:130:38 | ... == ... | false | C.cs:130:14:130:29 | ... = ... | non-null | | C.cs:130:13:130:38 | ... == ... | true | C.cs:130:14:130:29 | ... = ... | null | | C.cs:130:13:130:55 | ... \|\| ... | false | C.cs:130:13:130:38 | ... == ... | false | | C.cs:130:13:130:55 | ... \|\| ... | false | C.cs:130:43:130:55 | ... > ... | false | +| C.cs:130:14:130:29 | ... = ... | non-null | C.cs:130:14:130:15 | access to local variable ok | non-null | +| C.cs:130:14:130:29 | ... = ... | non-null | C.cs:130:20:130:28 | ... = ... | non-null | +| C.cs:130:14:130:29 | ... = ... | null | C.cs:130:14:130:15 | access to local variable ok | null | +| C.cs:130:14:130:29 | ... = ... | null | C.cs:130:20:130:28 | ... = ... | null | +| C.cs:130:20:130:28 | ... = ... | non-null | C.cs:130:20:130:21 | access to local variable xx | non-null | +| C.cs:130:20:130:28 | ... = ... | non-null | C.cs:130:25:130:28 | null | non-null | +| C.cs:130:20:130:28 | ... = ... | null | C.cs:130:20:130:21 | access to local variable xx | null | +| C.cs:130:20:130:28 | ... = ... | null | C.cs:130:25:130:28 | null | null | | C.cs:130:43:130:44 | access to local variable ok | non-null | C.cs:130:20:130:28 | ... = ... | non-null | | C.cs:130:43:130:44 | access to local variable ok | null | C.cs:130:20:130:28 | ... = ... | null | +| C.cs:137:16:137:25 | String ok2 = ... | non-null | C.cs:137:16:137:18 | access to local variable ok2 | non-null | +| C.cs:137:16:137:25 | String ok2 = ... | null | C.cs:137:16:137:18 | access to local variable ok2 | null | | C.cs:138:13:138:48 | ... \|\| ... | false | C.cs:138:13:138:30 | call to local function Foo | false | | C.cs:138:13:138:48 | ... \|\| ... | false | C.cs:138:35:138:48 | ... > ... | false | +| C.cs:138:17:138:29 | ... = ... | non-null | C.cs:138:17:138:19 | access to local variable ok2 | non-null | +| C.cs:138:17:138:29 | ... = ... | non-null | C.cs:138:23:138:29 | "hello" | non-null | +| C.cs:138:17:138:29 | ... = ... | null | C.cs:138:17:138:19 | access to local variable ok2 | null | +| C.cs:138:17:138:29 | ... = ... | null | C.cs:138:23:138:29 | "hello" | null | | C.cs:138:35:138:37 | access to local variable ok2 | non-null | C.cs:138:23:138:29 | "hello" | non-null | | C.cs:138:35:138:37 | access to local variable ok2 | null | C.cs:138:23:138:29 | "hello" | null | +| C.cs:145:16:145:25 | String ok3 = ... | non-null | C.cs:145:16:145:18 | access to local variable ok3 | non-null | +| C.cs:145:16:145:25 | String ok3 = ... | null | C.cs:145:16:145:18 | access to local variable ok3 | null | | C.cs:146:13:146:39 | ... != ... | false | C.cs:146:14:146:30 | ... = ... | null | | C.cs:146:13:146:39 | ... != ... | true | C.cs:146:14:146:30 | ... = ... | non-null | | C.cs:146:13:146:57 | ... && ... | true | C.cs:146:13:146:39 | ... != ... | true | | C.cs:146:13:146:57 | ... && ... | true | C.cs:146:44:146:57 | ... > ... | true | +| C.cs:146:14:146:30 | ... = ... | non-null | C.cs:146:14:146:15 | access to local variable xx | non-null | +| C.cs:146:14:146:30 | ... = ... | non-null | C.cs:146:20:146:29 | ... = ... | non-null | +| C.cs:146:14:146:30 | ... = ... | null | C.cs:146:14:146:15 | access to local variable xx | null | +| C.cs:146:14:146:30 | ... = ... | null | C.cs:146:20:146:29 | ... = ... | null | +| C.cs:146:20:146:29 | ... = ... | non-null | C.cs:146:20:146:22 | access to local variable ok3 | non-null | +| C.cs:146:20:146:29 | ... = ... | non-null | C.cs:146:26:146:29 | null | non-null | +| C.cs:146:20:146:29 | ... = ... | null | C.cs:146:20:146:22 | access to local variable ok3 | null | +| C.cs:146:20:146:29 | ... = ... | null | C.cs:146:26:146:29 | null | null | | C.cs:146:44:146:46 | access to local variable ok3 | non-null | C.cs:146:26:146:29 | null | non-null | | C.cs:146:44:146:46 | access to local variable ok3 | null | C.cs:146:26:146:29 | null | null | +| C.cs:152:13:152:18 | String s = ... | non-null | C.cs:152:13:152:13 | access to local variable s | non-null | +| C.cs:152:13:152:18 | String s = ... | null | C.cs:152:13:152:13 | access to local variable s | null | +| C.cs:156:13:156:20 | ... = ... | non-null | C.cs:156:13:156:13 | access to local variable s | non-null | +| C.cs:156:13:156:20 | ... = ... | non-null | C.cs:156:17:156:20 | null | non-null | +| C.cs:156:13:156:20 | ... = ... | null | C.cs:156:13:156:13 | access to local variable s | null | +| C.cs:156:13:156:20 | ... = ... | null | C.cs:156:17:156:20 | null | null | | C.cs:158:16:158:16 | access to local variable s | non-null | C.cs:156:17:156:20 | null | non-null | | C.cs:158:16:158:16 | access to local variable s | null | C.cs:156:17:156:20 | null | null | | C.cs:158:16:158:24 | ... != ... | false | C.cs:158:16:158:16 | access to local variable s | null | | C.cs:158:16:158:24 | ... != ... | true | C.cs:158:16:158:16 | access to local variable s | non-null | +| C.cs:160:9:160:16 | ... = ... | non-null | C.cs:160:9:160:9 | access to local variable s | non-null | +| C.cs:160:9:160:16 | ... = ... | non-null | C.cs:160:13:160:16 | null | non-null | +| C.cs:160:9:160:16 | ... = ... | null | C.cs:160:9:160:9 | access to local variable s | null | +| C.cs:160:9:160:16 | ... = ... | null | C.cs:160:13:160:16 | null | null | +| C.cs:164:13:164:20 | ... = ... | non-null | C.cs:164:13:164:13 | access to local variable s | non-null | +| C.cs:164:13:164:20 | ... = ... | non-null | C.cs:164:17:164:20 | null | non-null | +| C.cs:164:13:164:20 | ... = ... | null | C.cs:164:13:164:13 | access to local variable s | null | +| C.cs:164:13:164:20 | ... = ... | null | C.cs:164:17:164:20 | null | null | | C.cs:166:16:166:16 | access to local variable s | non-null | C.cs:164:17:164:20 | null | non-null | | C.cs:166:16:166:16 | access to local variable s | null | C.cs:164:17:164:20 | null | null | | C.cs:166:16:166:24 | ... != ... | false | C.cs:166:16:166:16 | access to local variable s | null | | C.cs:166:16:166:24 | ... != ... | true | C.cs:166:16:166:16 | access to local variable s | non-null | +| C.cs:168:9:168:16 | ... = ... | non-null | C.cs:168:9:168:9 | access to local variable s | non-null | +| C.cs:168:9:168:16 | ... = ... | non-null | C.cs:168:13:168:16 | null | non-null | +| C.cs:168:9:168:16 | ... = ... | null | C.cs:168:9:168:9 | access to local variable s | null | +| C.cs:168:9:168:16 | ... = ... | null | C.cs:168:13:168:16 | null | null | | C.cs:171:13:171:13 | access to local variable s | non-null | C.cs:168:13:168:16 | null | non-null | | C.cs:171:13:171:13 | access to local variable s | null | C.cs:168:13:168:16 | null | null | | C.cs:173:16:173:16 | access to local variable s | non-null | C.cs:168:13:168:16 | null | non-null | | C.cs:173:16:173:16 | access to local variable s | null | C.cs:168:13:168:16 | null | null | | C.cs:173:16:173:24 | ... != ... | false | C.cs:173:16:173:16 | access to local variable s | null | | C.cs:173:16:173:24 | ... != ... | true | C.cs:173:16:173:16 | access to local variable s | non-null | +| C.cs:175:9:175:14 | ... = ... | non-null | C.cs:175:9:175:9 | access to local variable s | non-null | +| C.cs:175:9:175:14 | ... = ... | non-null | C.cs:175:13:175:14 | "" | non-null | +| C.cs:175:9:175:14 | ... = ... | null | C.cs:175:9:175:9 | access to local variable s | null | +| C.cs:175:9:175:14 | ... = ... | null | C.cs:175:13:175:14 | "" | null | +| C.cs:179:13:179:20 | ... = ... | non-null | C.cs:179:13:179:13 | access to local variable s | non-null | +| C.cs:179:13:179:20 | ... = ... | non-null | C.cs:179:17:179:20 | null | non-null | +| C.cs:179:13:179:20 | ... = ... | null | C.cs:179:13:179:13 | access to local variable s | null | +| C.cs:179:13:179:20 | ... = ... | null | C.cs:179:17:179:20 | null | null | +| C.cs:186:13:186:18 | String s = ... | non-null | C.cs:186:13:186:13 | access to local variable s | non-null | +| C.cs:186:13:186:18 | String s = ... | null | C.cs:186:13:186:13 | access to local variable s | null | | C.cs:187:16:187:24 | ... != ... | false | C.cs:187:16:187:16 | access to local variable s | null | | C.cs:187:16:187:24 | ... != ... | true | C.cs:187:16:187:16 | access to local variable s | non-null | +| C.cs:190:13:190:20 | ... = ... | non-null | C.cs:190:13:190:13 | access to local variable s | non-null | +| C.cs:190:13:190:20 | ... = ... | non-null | C.cs:190:17:190:20 | null | non-null | +| C.cs:190:13:190:20 | ... = ... | null | C.cs:190:13:190:13 | access to local variable s | null | +| C.cs:190:13:190:20 | ... = ... | null | C.cs:190:17:190:20 | null | null | +| C.cs:193:13:193:20 | Boolean b = ... | false | C.cs:193:13:193:13 | access to local variable b | false | +| C.cs:193:13:193:20 | Boolean b = ... | true | C.cs:193:13:193:13 | access to local variable b | true | +| C.cs:194:9:194:16 | ... = ... | non-null | C.cs:194:9:194:9 | access to local variable s | non-null | +| C.cs:194:9:194:16 | ... = ... | non-null | C.cs:194:13:194:16 | null | non-null | +| C.cs:194:9:194:16 | ... = ... | null | C.cs:194:9:194:9 | access to local variable s | null | +| C.cs:194:9:194:16 | ... = ... | null | C.cs:194:13:194:16 | null | null | +| C.cs:198:13:198:20 | ... = ... | non-null | C.cs:198:13:198:13 | access to local variable s | non-null | +| C.cs:198:13:198:20 | ... = ... | non-null | C.cs:198:17:198:20 | null | non-null | +| C.cs:198:13:198:20 | ... = ... | null | C.cs:198:13:198:13 | access to local variable s | null | +| C.cs:198:13:198:20 | ... = ... | null | C.cs:198:17:198:20 | null | null | +| C.cs:201:9:201:14 | ... = ... | non-null | C.cs:201:9:201:9 | access to local variable s | non-null | +| C.cs:201:9:201:14 | ... = ... | non-null | C.cs:201:13:201:14 | "" | non-null | +| C.cs:201:9:201:14 | ... = ... | null | C.cs:201:9:201:9 | access to local variable s | null | +| C.cs:201:9:201:14 | ... = ... | null | C.cs:201:13:201:14 | "" | null | +| C.cs:205:13:205:20 | ... = ... | non-null | C.cs:205:13:205:13 | access to local variable s | non-null | +| C.cs:205:13:205:20 | ... = ... | non-null | C.cs:205:17:205:20 | null | non-null | +| C.cs:205:13:205:20 | ... = ... | null | C.cs:205:13:205:13 | access to local variable s | null | +| C.cs:205:13:205:20 | ... = ... | null | C.cs:205:17:205:20 | null | null | +| C.cs:211:13:211:35 | String s = ... | non-null | C.cs:211:13:211:13 | access to local variable s | non-null | +| C.cs:211:13:211:35 | String s = ... | null | C.cs:211:13:211:13 | access to local variable s | null | | C.cs:212:13:212:13 | access to local variable s | non-null | C.cs:211:17:211:35 | ... ? ... : ... | non-null | | C.cs:212:13:212:13 | access to local variable s | null | C.cs:211:17:211:35 | ... ? ... : ... | null | | C.cs:212:13:212:21 | ... != ... | false | C.cs:212:13:212:13 | access to local variable s | null | | C.cs:212:13:212:21 | ... != ... | true | C.cs:212:13:212:13 | access to local variable s | non-null | | C.cs:214:13:214:13 | access to local variable s | non-null | C.cs:211:17:211:35 | ... ? ... : ... | non-null | | C.cs:214:13:214:13 | access to local variable s | null | C.cs:211:17:211:35 | ... ? ... : ... | null | +| C.cs:215:13:215:20 | ... = ... | non-null | C.cs:215:13:215:13 | access to local variable s | non-null | +| C.cs:215:13:215:20 | ... = ... | non-null | C.cs:215:17:215:20 | null | non-null | +| C.cs:215:13:215:20 | ... = ... | null | C.cs:215:13:215:13 | access to local variable s | null | +| C.cs:215:13:215:20 | ... = ... | null | C.cs:215:17:215:20 | null | null | | C.cs:218:13:218:21 | ... == ... | false | C.cs:218:13:218:13 | access to local variable s | non-null | | C.cs:218:13:218:21 | ... == ... | true | C.cs:218:13:218:13 | access to local variable s | null | +| C.cs:221:9:221:14 | ... = ... | non-null | C.cs:221:9:221:9 | access to local variable s | non-null | +| C.cs:221:9:221:14 | ... = ... | non-null | C.cs:221:13:221:14 | "" | non-null | +| C.cs:221:9:221:14 | ... = ... | null | C.cs:221:9:221:9 | access to local variable s | null | +| C.cs:221:9:221:14 | ... = ... | null | C.cs:221:13:221:14 | "" | null | | C.cs:222:13:222:13 | access to local variable s | non-null | C.cs:221:13:221:14 | "" | non-null | | C.cs:222:13:222:13 | access to local variable s | null | C.cs:221:13:221:14 | "" | null | | C.cs:222:13:222:21 | ... != ... | false | C.cs:222:13:222:13 | access to local variable s | null | @@ -279,14 +513,52 @@ | C.cs:222:13:222:42 | ... && ... | true | C.cs:222:26:222:42 | ... == ... | true | | C.cs:222:26:222:26 | access to local variable s | non-null | C.cs:221:13:221:14 | "" | non-null | | C.cs:222:26:222:26 | access to local variable s | null | C.cs:221:13:221:14 | "" | null | +| C.cs:223:13:223:20 | ... = ... | non-null | C.cs:223:13:223:13 | access to local variable s | non-null | +| C.cs:223:13:223:20 | ... = ... | non-null | C.cs:223:17:223:20 | null | non-null | +| C.cs:223:13:223:20 | ... = ... | null | C.cs:223:13:223:13 | access to local variable s | null | +| C.cs:223:13:223:20 | ... = ... | null | C.cs:223:17:223:20 | null | null | +| C.cs:230:14:230:19 | ... = ... | non-null | C.cs:230:14:230:14 | access to local variable s | non-null | +| C.cs:230:14:230:19 | ... = ... | non-null | C.cs:230:18:230:19 | "" | non-null | +| C.cs:230:14:230:19 | ... = ... | null | C.cs:230:14:230:14 | access to local variable s | null | +| C.cs:230:14:230:19 | ... = ... | null | C.cs:230:18:230:19 | "" | null | | C.cs:230:22:230:30 | ... != ... | false | C.cs:230:22:230:22 | access to local variable s | null | | C.cs:230:22:230:30 | ... != ... | true | C.cs:230:22:230:22 | access to local variable s | non-null | +| C.cs:230:33:230:40 | ... = ... | non-null | C.cs:230:33:230:33 | access to local variable s | non-null | +| C.cs:230:33:230:40 | ... = ... | non-null | C.cs:230:37:230:40 | null | non-null | +| C.cs:230:33:230:40 | ... = ... | null | C.cs:230:33:230:33 | access to local variable s | null | +| C.cs:230:33:230:40 | ... = ... | null | C.cs:230:37:230:40 | null | null | +| C.cs:236:14:236:21 | ... = ... | non-null | C.cs:236:14:236:14 | access to local variable s | non-null | +| C.cs:236:14:236:21 | ... = ... | non-null | C.cs:236:18:236:21 | null | non-null | +| C.cs:236:14:236:21 | ... = ... | null | C.cs:236:14:236:14 | access to local variable s | null | +| C.cs:236:14:236:21 | ... = ... | null | C.cs:236:18:236:21 | null | null | | C.cs:236:24:236:32 | ... == ... | false | C.cs:236:24:236:24 | access to local variable s | non-null | | C.cs:236:24:236:32 | ... == ... | true | C.cs:236:24:236:24 | access to local variable s | null | +| C.cs:236:35:236:42 | ... = ... | non-null | C.cs:236:35:236:35 | access to local variable s | non-null | +| C.cs:236:35:236:42 | ... = ... | non-null | C.cs:236:39:236:42 | null | non-null | +| C.cs:236:35:236:42 | ... = ... | null | C.cs:236:35:236:35 | access to local variable s | null | +| C.cs:236:35:236:42 | ... = ... | null | C.cs:236:39:236:42 | null | null | +| C.cs:241:14:241:19 | ... = ... | non-null | C.cs:241:14:241:14 | access to local variable s | non-null | +| C.cs:241:14:241:19 | ... = ... | non-null | C.cs:241:18:241:19 | "" | non-null | +| C.cs:241:14:241:19 | ... = ... | null | C.cs:241:14:241:14 | access to local variable s | null | +| C.cs:241:14:241:19 | ... = ... | null | C.cs:241:18:241:19 | "" | null | +| C.cs:241:24:241:31 | ... = ... | non-null | C.cs:241:24:241:24 | access to local variable s | non-null | +| C.cs:241:24:241:31 | ... = ... | non-null | C.cs:241:28:241:31 | null | non-null | +| C.cs:241:24:241:31 | ... = ... | null | C.cs:241:24:241:24 | access to local variable s | null | +| C.cs:241:24:241:31 | ... = ... | null | C.cs:241:28:241:31 | null | null | +| C.cs:249:15:249:22 | Int32[] a = ... | non-null | C.cs:249:15:249:15 | access to local variable a | non-null | +| C.cs:249:15:249:22 | Int32[] a = ... | null | C.cs:249:15:249:15 | access to local variable a | null | | C.cs:250:9:250:9 | access to local variable a | non-null | C.cs:249:19:249:22 | null | non-null | | C.cs:250:9:250:9 | access to local variable a | null | C.cs:249:19:249:22 | null | null | +| C.cs:252:9:252:23 | ... = ... | non-null | C.cs:252:9:252:9 | access to local variable a | non-null | +| C.cs:252:9:252:23 | ... = ... | non-null | C.cs:252:13:252:23 | array creation of type Int32[] | non-null | +| C.cs:252:9:252:23 | ... = ... | null | C.cs:252:9:252:9 | access to local variable a | null | +| C.cs:252:9:252:23 | ... = ... | null | C.cs:252:13:252:23 | array creation of type Int32[] | null | | C.cs:253:9:253:9 | access to local variable a | non-null | C.cs:252:13:252:23 | array creation of type Int32[] | non-null | | C.cs:253:9:253:9 | access to local variable a | null | C.cs:252:13:252:23 | array creation of type Int32[] | null | +| C.cs:258:15:258:23 | Int32[] ia = ... | non-null | C.cs:258:15:258:16 | access to local variable ia | non-null | +| C.cs:258:15:258:23 | Int32[] ia = ... | null | C.cs:258:15:258:16 | access to local variable ia | null | +| C.cs:259:18:259:26 | String[] sa = ... | non-null | C.cs:259:18:259:19 | access to local variable sa | non-null | +| C.cs:259:18:259:26 | String[] sa = ... | null | C.cs:259:18:259:19 | access to local variable sa | null | | C.cs:261:9:261:10 | access to local variable ia | non-null | C.cs:258:20:258:23 | null | non-null | | C.cs:261:9:261:10 | access to local variable ia | null | C.cs:258:20:258:23 | null | null | | C.cs:262:20:262:21 | access to local variable sa | non-null | C.cs:259:23:259:26 | null | non-null | @@ -295,6 +567,18 @@ | C.cs:264:9:264:10 | access to local variable ia | null | C.cs:258:20:258:23 | null | null | | C.cs:265:16:265:17 | access to local variable sa | non-null | C.cs:259:23:259:26 | null | non-null | | C.cs:265:16:265:17 | access to local variable sa | null | C.cs:259:23:259:26 | null | null | +| C.cs:271:9:271:18 | ... = ... | false | C.cs:271:9:271:14 | access to field m | false | +| C.cs:271:9:271:18 | ... = ... | false | C.cs:271:18:271:18 | access to parameter m | false | +| C.cs:271:9:271:18 | ... = ... | true | C.cs:271:9:271:14 | access to field m | true | +| C.cs:271:9:271:18 | ... = ... | true | C.cs:271:18:271:18 | access to parameter m | true | +| D.cs:10:9:10:22 | ... = ... | false | D.cs:10:9:10:18 | access to field maybe | false | +| D.cs:10:9:10:22 | ... = ... | false | D.cs:10:22:10:22 | access to parameter b | false | +| D.cs:10:9:10:22 | ... = ... | true | D.cs:10:9:10:18 | access to field maybe | true | +| D.cs:10:9:10:22 | ... = ... | true | D.cs:10:22:10:22 | access to parameter b | true | +| D.cs:11:9:11:21 | ... = ... | false | D.cs:11:9:11:17 | access to field flag | false | +| D.cs:11:9:11:21 | ... = ... | false | D.cs:11:21:11:21 | access to parameter f | false | +| D.cs:11:9:11:21 | ... = ... | true | D.cs:11:9:11:17 | access to field flag | true | +| D.cs:11:9:11:21 | ... = ... | true | D.cs:11:21:11:21 | access to parameter f | true | | D.cs:28:13:28:25 | ... != ... | false | D.cs:28:13:28:17 | access to parameter param | null | | D.cs:28:13:28:25 | ... != ... | true | D.cs:28:13:28:17 | access to parameter param | non-null | | D.cs:37:13:37:23 | ... is ... | true | D.cs:37:13:37:13 | access to parameter x | non-null | @@ -302,21 +586,34 @@ | D.cs:38:13:38:21 | ... == ... | true | D.cs:38:13:38:13 | access to parameter x | null | | D.cs:39:16:39:24 | ... == ... | false | D.cs:39:16:39:16 | access to parameter x | non-null | | D.cs:39:16:39:24 | ... == ... | true | D.cs:39:16:39:16 | access to parameter x | null | +| D.cs:44:13:44:44 | Object o1 = ... | non-null | D.cs:44:13:44:14 | access to local variable o1 | non-null | +| D.cs:44:13:44:44 | Object o1 = ... | null | D.cs:44:13:44:14 | access to local variable o1 | null | | D.cs:45:13:45:14 | access to local variable o1 | non-null | D.cs:44:18:44:44 | ... ? ... : ... | non-null | | D.cs:45:13:45:14 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | | D.cs:45:13:45:22 | ... != ... | false | D.cs:45:13:45:14 | access to local variable o1 | null | | D.cs:45:13:45:22 | ... != ... | true | D.cs:45:13:45:14 | access to local variable o1 | non-null | | D.cs:45:25:45:26 | access to local variable o1 | non-null | D.cs:44:18:44:44 | ... ? ... : ... | non-null | | D.cs:45:25:45:26 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | +| D.cs:47:13:47:34 | String o2 = ... | non-null | D.cs:47:13:47:14 | access to local variable o2 | non-null | +| D.cs:47:13:47:34 | String o2 = ... | null | D.cs:47:13:47:14 | access to local variable o2 | null | | D.cs:48:13:48:14 | access to local variable o2 | non-null | D.cs:47:18:47:34 | ... ? ... : ... | non-null | | D.cs:48:13:48:14 | access to local variable o2 | null | D.cs:47:18:47:34 | ... ? ... : ... | null | +| D.cs:48:13:48:24 | ... is ... | false | D.cs:48:13:48:14 | access to local variable o2 | null | | D.cs:48:13:48:24 | ... is ... | true | D.cs:48:13:48:14 | access to local variable o2 | non-null | | D.cs:48:27:48:28 | access to local variable o2 | non-null | D.cs:47:18:47:34 | ... ? ... : ... | non-null | | D.cs:48:27:48:28 | access to local variable o2 | null | D.cs:47:18:47:34 | ... ? ... : ... | null | +| D.cs:50:16:50:24 | Object o3 = ... | non-null | D.cs:50:16:50:17 | access to local variable o3 | non-null | +| D.cs:50:16:50:24 | Object o3 = ... | null | D.cs:50:16:50:17 | access to local variable o3 | null | | D.cs:51:13:51:44 | ... != ... | false | D.cs:51:14:51:35 | ... = ... | null | | D.cs:51:13:51:44 | ... != ... | true | D.cs:51:14:51:35 | ... = ... | non-null | +| D.cs:51:14:51:35 | ... = ... | non-null | D.cs:51:14:51:15 | access to local variable o3 | non-null | +| D.cs:51:14:51:35 | ... = ... | non-null | D.cs:51:19:51:35 | ... ? ... : ... | non-null | +| D.cs:51:14:51:35 | ... = ... | null | D.cs:51:14:51:15 | access to local variable o3 | null | +| D.cs:51:14:51:35 | ... = ... | null | D.cs:51:19:51:35 | ... ? ... : ... | null | | D.cs:52:13:52:14 | access to local variable o3 | non-null | D.cs:51:19:51:35 | ... ? ... : ... | non-null | | D.cs:52:13:52:14 | access to local variable o3 | null | D.cs:51:19:51:35 | ... ? ... : ... | null | +| D.cs:54:13:54:34 | String o4 = ... | non-null | D.cs:54:13:54:14 | access to local variable o4 | non-null | +| D.cs:54:13:54:34 | String o4 = ... | null | D.cs:54:13:54:14 | access to local variable o4 | null | | D.cs:55:13:55:42 | ... != ... | false | D.cs:55:14:55:32 | ... && ... | false | | D.cs:55:13:55:42 | ... != ... | true | D.cs:55:14:55:32 | ... && ... | true | | D.cs:55:14:55:32 | ... && ... | true | D.cs:55:14:55:18 | ... > ... | true | @@ -327,6 +624,8 @@ | D.cs:55:23:55:32 | ... != ... | true | D.cs:55:23:55:24 | access to local variable o4 | non-null | | D.cs:56:13:56:14 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:56:13:56:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:58:13:58:41 | String o5 = ... | non-null | D.cs:58:13:58:14 | access to local variable o5 | non-null | +| D.cs:58:13:58:41 | String o5 = ... | null | D.cs:58:13:58:14 | access to local variable o5 | null | | D.cs:58:19:58:20 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:58:19:58:20 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | | D.cs:58:19:58:28 | ... != ... | false | D.cs:58:19:58:20 | access to local variable o4 | null | @@ -343,6 +642,8 @@ | D.cs:61:13:61:22 | ... != ... | true | D.cs:61:13:61:14 | access to local variable o4 | non-null | | D.cs:62:13:62:14 | access to local variable o5 | non-null | D.cs:58:18:58:41 | ... ? ... : ... | non-null | | D.cs:62:13:62:14 | access to local variable o5 | null | D.cs:58:18:58:41 | ... ? ... : ... | null | +| D.cs:64:13:64:34 | String o6 = ... | non-null | D.cs:64:13:64:14 | access to local variable o6 | non-null | +| D.cs:64:13:64:34 | String o6 = ... | null | D.cs:64:13:64:14 | access to local variable o6 | null | | D.cs:65:13:65:29 | !... | false | D.cs:65:14:65:29 | call to method CustomIsNull | true | | D.cs:65:13:65:29 | !... | true | D.cs:65:14:65:29 | call to method CustomIsNull | false | | D.cs:65:14:65:29 | call to method CustomIsNull | false | D.cs:65:27:65:28 | access to local variable o6 | non-null | @@ -351,6 +652,10 @@ | D.cs:65:27:65:28 | access to local variable o6 | null | D.cs:64:18:64:34 | ... ? ... : ... | null | | D.cs:66:13:66:14 | access to local variable o6 | non-null | D.cs:64:18:64:34 | ... ? ... : ... | non-null | | D.cs:66:13:66:14 | access to local variable o6 | null | D.cs:64:18:64:34 | ... ? ... : ... | null | +| D.cs:68:13:68:34 | String o7 = ... | non-null | D.cs:68:13:68:14 | access to local variable o7 | non-null | +| D.cs:68:13:68:34 | String o7 = ... | null | D.cs:68:13:68:14 | access to local variable o7 | null | +| D.cs:69:13:69:36 | Boolean ok = ... | false | D.cs:69:13:69:14 | access to local variable ok | false | +| D.cs:69:13:69:36 | Boolean ok = ... | true | D.cs:69:13:69:14 | access to local variable ok | true | | D.cs:69:18:69:19 | access to local variable o7 | non-null | D.cs:68:18:68:34 | ... ? ... : ... | non-null | | D.cs:69:18:69:19 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | | D.cs:69:18:69:27 | ... != ... | false | D.cs:69:18:69:19 | access to local variable o7 | null | @@ -363,6 +668,8 @@ | D.cs:71:13:71:14 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | | D.cs:73:13:73:14 | access to local variable o7 | non-null | D.cs:68:18:68:34 | ... ? ... : ... | non-null | | D.cs:73:13:73:14 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | +| D.cs:75:13:75:34 | String o8 = ... | non-null | D.cs:75:13:75:14 | access to local variable o8 | non-null | +| D.cs:75:13:75:34 | String o8 = ... | null | D.cs:75:13:75:14 | access to local variable o8 | null | | D.cs:76:21:76:22 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:76:21:76:22 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | | D.cs:76:21:76:30 | ... == ... | false | D.cs:76:21:76:22 | access to local variable o8 | non-null | @@ -375,8 +682,14 @@ | D.cs:82:13:82:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | | D.cs:84:13:84:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:84:13:84:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:89:15:89:44 | Int32[] xs = ... | non-null | D.cs:89:15:89:16 | access to local variable xs | non-null | +| D.cs:89:15:89:44 | Int32[] xs = ... | null | D.cs:89:15:89:16 | access to local variable xs | null | | D.cs:91:13:91:14 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | | D.cs:91:13:91:14 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:94:13:94:29 | ... = ... | false | D.cs:94:13:94:17 | access to field maybe | false | +| D.cs:94:13:94:29 | ... = ... | false | D.cs:94:21:94:29 | ... > ... | false | +| D.cs:94:13:94:29 | ... = ... | true | D.cs:94:13:94:17 | access to field maybe | true | +| D.cs:94:13:94:29 | ... = ... | true | D.cs:94:21:94:29 | ... > ... | true | | D.cs:94:21:94:22 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | | D.cs:94:21:94:22 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | | D.cs:98:21:98:22 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | @@ -397,6 +710,12 @@ | D.cs:111:13:111:14 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | | D.cs:111:21:111:22 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | | D.cs:111:21:111:22 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:117:13:117:32 | String x = ... | non-null | D.cs:117:13:117:13 | access to local variable x | non-null | +| D.cs:117:13:117:32 | String x = ... | null | D.cs:117:13:117:13 | access to local variable x | null | +| D.cs:118:9:118:30 | ... = ... | non-null | D.cs:118:9:118:9 | access to local variable x | non-null | +| D.cs:118:9:118:30 | ... = ... | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | +| D.cs:118:9:118:30 | ... = ... | null | D.cs:118:9:118:9 | access to local variable x | null | +| D.cs:118:9:118:30 | ... = ... | null | D.cs:118:13:118:30 | ... ? ... : ... | null | | D.cs:118:13:118:13 | access to local variable x | non-null | D.cs:117:17:117:32 | ... ? ... : ... | non-null | | D.cs:118:13:118:13 | access to local variable x | null | D.cs:117:17:117:32 | ... ? ... : ... | null | | D.cs:118:13:118:21 | ... == ... | false | D.cs:118:13:118:13 | access to local variable x | non-null | @@ -419,8 +738,28 @@ | D.cs:139:13:139:21 | ... != ... | true | D.cs:139:13:139:13 | access to parameter a | non-null | | D.cs:152:17:152:27 | ... != ... | false | D.cs:152:17:152:19 | access to parameter obj | null | | D.cs:152:17:152:27 | ... != ... | true | D.cs:152:17:152:19 | access to parameter obj | non-null | +| D.cs:163:16:163:25 | Object obj = ... | non-null | D.cs:163:16:163:18 | access to local variable obj | non-null | +| D.cs:163:16:163:25 | Object obj = ... | null | D.cs:163:16:163:18 | access to local variable obj | null | +| D.cs:166:13:166:27 | ... = ... | non-null | D.cs:166:13:166:15 | access to local variable obj | non-null | +| D.cs:166:13:166:27 | ... = ... | non-null | D.cs:166:19:166:27 | call to method MkMaybe | non-null | +| D.cs:166:13:166:27 | ... = ... | null | D.cs:166:13:166:15 | access to local variable obj | null | +| D.cs:166:13:166:27 | ... = ... | null | D.cs:166:19:166:27 | call to method MkMaybe | null | +| D.cs:173:16:173:26 | Object obj2 = ... | non-null | D.cs:173:16:173:19 | access to local variable obj2 | non-null | +| D.cs:173:16:173:26 | Object obj2 = ... | null | D.cs:173:16:173:19 | access to local variable obj2 | null | +| D.cs:176:13:176:28 | ... = ... | non-null | D.cs:176:13:176:16 | access to local variable obj2 | non-null | +| D.cs:176:13:176:28 | ... = ... | non-null | D.cs:176:20:176:28 | call to method MkMaybe | non-null | +| D.cs:176:13:176:28 | ... = ... | null | D.cs:176:13:176:16 | access to local variable obj2 | null | +| D.cs:176:13:176:28 | ... = ... | null | D.cs:176:20:176:28 | call to method MkMaybe | null | | D.cs:182:9:182:12 | access to local variable obj2 | non-null | D.cs:176:20:176:28 | call to method MkMaybe | non-null | | D.cs:182:9:182:12 | access to local variable obj2 | null | D.cs:176:20:176:28 | call to method MkMaybe | null | +| D.cs:184:16:184:26 | Object obj3 = ... | non-null | D.cs:184:16:184:19 | access to local variable obj3 | non-null | +| D.cs:184:16:184:26 | Object obj3 = ... | null | D.cs:184:16:184:19 | access to local variable obj3 | null | +| D.cs:187:13:187:28 | ... = ... | non-null | D.cs:187:13:187:16 | access to local variable obj3 | non-null | +| D.cs:187:13:187:28 | ... = ... | non-null | D.cs:187:20:187:28 | call to method MkMaybe | non-null | +| D.cs:187:13:187:28 | ... = ... | null | D.cs:187:13:187:16 | access to local variable obj3 | null | +| D.cs:187:13:187:28 | ... = ... | null | D.cs:187:20:187:28 | call to method MkMaybe | null | +| D.cs:195:13:195:28 | Object o = ... | non-null | D.cs:195:13:195:13 | access to local variable o | non-null | +| D.cs:195:13:195:28 | Object o = ... | null | D.cs:195:13:195:13 | access to local variable o | null | | D.cs:196:13:196:13 | access to local variable o | non-null | D.cs:195:17:195:28 | object creation of type Object | non-null | | D.cs:196:13:196:13 | access to local variable o | null | D.cs:195:17:195:28 | object creation of type Object | null | | D.cs:196:13:196:21 | ... == ... | false | D.cs:196:13:196:13 | access to local variable o | non-null | @@ -431,6 +770,10 @@ | D.cs:198:9:198:9 | access to local variable o | null | D.cs:195:17:195:28 | object creation of type Object | null | | D.cs:206:17:206:25 | ... == ... | false | D.cs:206:17:206:17 | access to local variable e | non-null | | D.cs:206:17:206:25 | ... == ... | true | D.cs:206:17:206:17 | access to local variable e | null | +| D.cs:211:16:211:23 | Object n = ... | non-null | D.cs:211:16:211:16 | access to local variable n | non-null | +| D.cs:211:16:211:23 | Object n = ... | null | D.cs:211:16:211:16 | access to local variable n | null | +| D.cs:212:13:212:45 | Object o2 = ... | non-null | D.cs:212:13:212:14 | access to local variable o2 | non-null | +| D.cs:212:13:212:45 | Object o2 = ... | null | D.cs:212:13:212:14 | access to local variable o2 | null | | D.cs:212:18:212:18 | access to local variable n | non-null | D.cs:211:20:211:23 | null | non-null | | D.cs:212:18:212:18 | access to local variable n | null | D.cs:211:20:211:23 | null | null | | D.cs:212:18:212:26 | ... == ... | false | D.cs:212:18:212:18 | access to local variable n | non-null | @@ -439,6 +782,8 @@ | D.cs:212:45:212:45 | access to local variable n | null | D.cs:211:20:211:23 | null | null | | D.cs:213:9:213:10 | access to local variable o2 | non-null | D.cs:212:18:212:45 | ... ? ... : ... | non-null | | D.cs:213:9:213:10 | access to local variable o2 | null | D.cs:212:18:212:45 | ... ? ... : ... | null | +| D.cs:215:13:215:22 | String o3 = ... | non-null | D.cs:215:13:215:14 | access to local variable o3 | non-null | +| D.cs:215:13:215:22 | String o3 = ... | null | D.cs:215:13:215:14 | access to local variable o3 | null | | D.cs:216:13:216:14 | access to local variable o3 | non-null | D.cs:215:18:215:22 | "abc" | non-null | | D.cs:216:13:216:14 | access to local variable o3 | null | D.cs:215:18:215:22 | "abc" | null | | D.cs:216:13:216:22 | ... == ... | false | D.cs:216:13:216:14 | access to local variable o3 | non-null | @@ -447,6 +792,9 @@ | D.cs:217:13:217:14 | access to local variable o3 | null | D.cs:215:18:215:22 | "abc" | null | | D.cs:218:9:218:10 | access to local variable o3 | non-null | D.cs:215:18:215:22 | "abc" | non-null | | D.cs:218:9:218:10 | access to local variable o3 | null | D.cs:215:18:215:22 | "abc" | null | +| D.cs:220:13:220:26 | String o4 = ... | non-null | D.cs:220:13:220:14 | access to local variable o4 | non-null | +| D.cs:220:13:220:26 | String o4 = ... | null | D.cs:220:13:220:14 | access to local variable o4 | null | +| D.cs:220:18:220:26 | ... + ... | non-null | D.cs:220:18:220:19 | "" | non-null | | D.cs:220:18:220:26 | ... + ... | non-null | D.cs:220:23:220:26 | null | non-null | | D.cs:220:18:220:26 | ... + ... | null | D.cs:220:23:220:26 | null | null | | D.cs:221:13:221:14 | access to local variable o4 | non-null | D.cs:220:18:220:26 | ... + ... | non-null | @@ -457,31 +805,145 @@ | D.cs:222:13:222:14 | access to local variable o4 | null | D.cs:220:18:220:26 | ... + ... | null | | D.cs:223:9:223:10 | access to local variable o4 | non-null | D.cs:220:18:220:26 | ... + ... | non-null | | D.cs:223:9:223:10 | access to local variable o4 | null | D.cs:220:18:220:26 | ... + ... | null | +| D.cs:228:16:228:23 | Object o = ... | non-null | D.cs:228:16:228:16 | access to local variable o | non-null | +| D.cs:228:16:228:23 | Object o = ... | null | D.cs:228:16:228:16 | access to local variable o | null | +| D.cs:230:13:230:28 | ... = ... | non-null | D.cs:230:13:230:13 | access to local variable o | non-null | +| D.cs:230:13:230:28 | ... = ... | non-null | D.cs:230:17:230:28 | object creation of type Object | non-null | +| D.cs:230:13:230:28 | ... = ... | null | D.cs:230:13:230:13 | access to local variable o | null | +| D.cs:230:13:230:28 | ... = ... | null | D.cs:230:17:230:28 | object creation of type Object | null | +| D.cs:234:9:234:16 | ... = ... | non-null | D.cs:234:9:234:9 | access to local variable o | non-null | +| D.cs:234:9:234:16 | ... = ... | non-null | D.cs:234:13:234:16 | null | non-null | +| D.cs:234:9:234:16 | ... = ... | null | D.cs:234:9:234:9 | access to local variable o | null | +| D.cs:234:9:234:16 | ... = ... | null | D.cs:234:13:234:16 | null | null | +| D.cs:236:13:236:18 | ... = ... | non-null | D.cs:236:13:236:13 | access to local variable o | non-null | +| D.cs:236:13:236:18 | ... = ... | non-null | D.cs:236:17:236:18 | "" | non-null | +| D.cs:236:13:236:18 | ... = ... | null | D.cs:236:13:236:13 | access to local variable o | null | +| D.cs:236:13:236:18 | ... = ... | null | D.cs:236:17:236:18 | "" | null | +| D.cs:240:9:240:16 | ... = ... | non-null | D.cs:240:9:240:9 | access to local variable o | non-null | +| D.cs:240:9:240:16 | ... = ... | non-null | D.cs:240:13:240:16 | null | non-null | +| D.cs:240:9:240:16 | ... = ... | null | D.cs:240:9:240:9 | access to local variable o | null | +| D.cs:240:9:240:16 | ... = ... | null | D.cs:240:13:240:16 | null | null | +| D.cs:241:13:241:37 | String other = ... | non-null | D.cs:241:13:241:17 | access to local variable other | non-null | +| D.cs:241:13:241:37 | String other = ... | null | D.cs:241:13:241:17 | access to local variable other | null | | D.cs:242:13:242:17 | access to local variable other | non-null | D.cs:241:21:241:37 | ... ? ... : ... | non-null | | D.cs:242:13:242:17 | access to local variable other | null | D.cs:241:21:241:37 | ... ? ... : ... | null | | D.cs:242:13:242:25 | ... == ... | false | D.cs:242:13:242:17 | access to local variable other | non-null | | D.cs:242:13:242:25 | ... == ... | true | D.cs:242:13:242:17 | access to local variable other | null | +| D.cs:243:13:243:18 | ... = ... | non-null | D.cs:243:13:243:13 | access to local variable o | non-null | +| D.cs:243:13:243:18 | ... = ... | non-null | D.cs:243:17:243:18 | "" | non-null | +| D.cs:243:13:243:18 | ... = ... | null | D.cs:243:13:243:13 | access to local variable o | null | +| D.cs:243:13:243:18 | ... = ... | null | D.cs:243:17:243:18 | "" | null | | D.cs:244:13:244:17 | access to local variable other | non-null | D.cs:241:21:241:37 | ... ? ... : ... | non-null | | D.cs:244:13:244:17 | access to local variable other | null | D.cs:241:21:241:37 | ... ? ... : ... | null | | D.cs:244:13:244:25 | ... != ... | false | D.cs:244:13:244:17 | access to local variable other | null | | D.cs:244:13:244:25 | ... != ... | true | D.cs:244:13:244:17 | access to local variable other | non-null | +| D.cs:249:13:249:38 | String o2 = ... | non-null | D.cs:249:13:249:14 | access to local variable o2 | non-null | +| D.cs:249:13:249:38 | String o2 = ... | null | D.cs:249:13:249:14 | access to local variable o2 | null | +| D.cs:251:13:251:19 | ... = ... | non-null | D.cs:251:13:251:14 | access to local variable o2 | non-null | +| D.cs:251:13:251:19 | ... = ... | non-null | D.cs:251:18:251:19 | "" | non-null | +| D.cs:251:13:251:19 | ... = ... | null | D.cs:251:13:251:14 | access to local variable o2 | null | +| D.cs:251:13:251:19 | ... = ... | null | D.cs:251:18:251:19 | "" | null | | D.cs:253:13:253:14 | access to local variable o2 | non-null | D.cs:249:18:249:38 | ... ? ... : ... | non-null | | D.cs:253:13:253:14 | access to local variable o2 | null | D.cs:249:18:249:38 | ... ? ... : ... | null | +| D.cs:258:16:258:23 | Object o = ... | non-null | D.cs:258:16:258:16 | access to local variable o | non-null | +| D.cs:258:16:258:23 | Object o = ... | null | D.cs:258:16:258:16 | access to local variable o | null | +| D.cs:259:16:259:27 | Object other = ... | non-null | D.cs:259:16:259:20 | access to local variable other | non-null | +| D.cs:259:16:259:27 | Object other = ... | null | D.cs:259:16:259:20 | access to local variable other | null | +| D.cs:262:13:262:21 | ... = ... | non-null | D.cs:262:13:262:13 | access to local variable o | non-null | +| D.cs:262:13:262:21 | ... = ... | non-null | D.cs:262:17:262:21 | "abc" | non-null | +| D.cs:262:13:262:21 | ... = ... | null | D.cs:262:13:262:13 | access to local variable o | null | +| D.cs:262:13:262:21 | ... = ... | null | D.cs:262:17:262:21 | "abc" | null | +| D.cs:263:13:263:25 | ... = ... | non-null | D.cs:263:13:263:17 | access to local variable other | non-null | +| D.cs:263:13:263:25 | ... = ... | non-null | D.cs:263:21:263:25 | "def" | non-null | +| D.cs:263:13:263:25 | ... = ... | null | D.cs:263:13:263:17 | access to local variable other | null | +| D.cs:263:13:263:25 | ... = ... | null | D.cs:263:21:263:25 | "def" | null | | D.cs:266:13:266:27 | ... is ... | true | D.cs:266:13:266:17 | access to local variable other | non-null | +| D.cs:269:9:269:16 | ... = ... | non-null | D.cs:269:9:269:9 | access to local variable o | non-null | +| D.cs:269:9:269:16 | ... = ... | non-null | D.cs:269:13:269:16 | null | non-null | +| D.cs:269:9:269:16 | ... = ... | null | D.cs:269:9:269:9 | access to local variable o | null | +| D.cs:269:9:269:16 | ... = ... | null | D.cs:269:13:269:16 | null | null | +| D.cs:271:13:271:25 | Boolean found = ... | false | D.cs:271:13:271:17 | access to local variable found | false | +| D.cs:271:13:271:25 | Boolean found = ... | true | D.cs:271:13:271:17 | access to local variable found | true | +| D.cs:276:17:276:42 | ... = ... | non-null | D.cs:276:17:276:17 | access to local variable o | non-null | +| D.cs:276:17:276:42 | ... = ... | non-null | D.cs:276:21:276:42 | call to method ToString | non-null | +| D.cs:276:17:276:42 | ... = ... | null | D.cs:276:17:276:17 | access to local variable o | null | +| D.cs:276:17:276:42 | ... = ... | null | D.cs:276:21:276:42 | call to method ToString | null | +| D.cs:279:17:279:28 | ... = ... | false | D.cs:279:17:279:21 | access to local variable found | false | +| D.cs:279:17:279:28 | ... = ... | true | D.cs:279:17:279:21 | access to local variable found | true | +| D.cs:283:17:283:24 | ... = ... | non-null | D.cs:283:17:283:17 | access to local variable o | non-null | +| D.cs:283:17:283:24 | ... = ... | non-null | D.cs:283:21:283:24 | null | non-null | +| D.cs:283:17:283:24 | ... = ... | null | D.cs:283:17:283:17 | access to local variable o | null | +| D.cs:283:17:283:24 | ... = ... | null | D.cs:283:21:283:24 | null | null | +| D.cs:286:17:286:29 | ... = ... | false | D.cs:286:17:286:21 | access to local variable found | false | +| D.cs:286:17:286:29 | ... = ... | true | D.cs:286:17:286:21 | access to local variable found | true | +| D.cs:296:16:296:26 | Object prev = ... | non-null | D.cs:296:16:296:19 | access to local variable prev | non-null | +| D.cs:296:16:296:26 | Object prev = ... | null | D.cs:296:16:296:19 | access to local variable prev | null | +| D.cs:301:13:301:23 | ... = ... | non-null | D.cs:301:13:301:16 | access to local variable prev | non-null | +| D.cs:301:13:301:23 | ... = ... | non-null | D.cs:301:20:301:23 | (...) ... | non-null | +| D.cs:301:13:301:23 | ... = ... | null | D.cs:301:13:301:16 | access to local variable prev | null | +| D.cs:301:13:301:23 | ... = ... | null | D.cs:301:20:301:23 | (...) ... | null | +| D.cs:304:16:304:23 | String s = ... | non-null | D.cs:304:16:304:16 | access to local variable s | non-null | +| D.cs:304:16:304:23 | String s = ... | null | D.cs:304:16:304:16 | access to local variable s | null | +| D.cs:306:17:306:29 | Boolean s_null = ... | false | D.cs:306:17:306:22 | access to local variable s_null | false | +| D.cs:306:17:306:29 | Boolean s_null = ... | true | D.cs:306:17:306:22 | access to local variable s_null | true | +| D.cs:309:17:309:30 | ... = ... | false | D.cs:309:17:309:22 | access to local variable s_null | false | +| D.cs:309:17:309:30 | ... = ... | true | D.cs:309:17:309:22 | access to local variable s_null | true | +| D.cs:310:17:310:26 | ... = ... | non-null | D.cs:310:17:310:17 | access to local variable s | non-null | +| D.cs:310:17:310:26 | ... = ... | non-null | D.cs:310:21:310:26 | ... + ... | non-null | +| D.cs:310:17:310:26 | ... = ... | null | D.cs:310:17:310:17 | access to local variable s | null | +| D.cs:310:17:310:26 | ... = ... | null | D.cs:310:21:310:26 | ... + ... | null | +| D.cs:310:21:310:26 | ... + ... | non-null | D.cs:310:21:310:22 | "" | non-null | | D.cs:310:21:310:26 | ... + ... | non-null | D.cs:310:26:310:26 | access to parameter a | non-null | | D.cs:310:21:310:26 | ... + ... | null | D.cs:310:26:310:26 | access to parameter a | null | | D.cs:312:17:312:23 | !... | false | D.cs:312:18:312:23 | access to local variable s_null | true | | D.cs:312:17:312:23 | !... | true | D.cs:312:18:312:23 | access to local variable s_null | false | +| D.cs:316:16:316:23 | Object r = ... | non-null | D.cs:316:16:316:16 | access to local variable r | non-null | +| D.cs:316:16:316:23 | Object r = ... | null | D.cs:316:16:316:16 | access to local variable r | null | | D.cs:318:16:318:62 | ... && ... | true | D.cs:318:16:318:36 | ... == ... | true | | D.cs:318:16:318:62 | ... && ... | true | D.cs:318:41:318:62 | ... != ... | true | +| D.cs:320:13:320:25 | ... = ... | non-null | D.cs:320:13:320:13 | access to local variable r | non-null | +| D.cs:320:13:320:25 | ... = ... | non-null | D.cs:320:17:320:25 | call to method MkMaybe | non-null | +| D.cs:320:13:320:25 | ... = ... | null | D.cs:320:13:320:13 | access to local variable r | null | +| D.cs:320:13:320:25 | ... = ... | null | D.cs:320:17:320:25 | call to method MkMaybe | null | +| D.cs:335:16:335:25 | String msg = ... | non-null | D.cs:335:16:335:18 | access to local variable msg | non-null | +| D.cs:335:16:335:25 | String msg = ... | null | D.cs:335:16:335:18 | access to local variable msg | null | | D.cs:336:13:336:23 | ... == ... | false | D.cs:336:13:336:15 | access to parameter obj | non-null | | D.cs:336:13:336:23 | ... == ... | true | D.cs:336:13:336:15 | access to parameter obj | null | +| D.cs:337:13:337:23 | ... = ... | non-null | D.cs:337:13:337:15 | access to local variable msg | non-null | +| D.cs:337:13:337:23 | ... = ... | non-null | D.cs:337:19:337:23 | "foo" | non-null | +| D.cs:337:13:337:23 | ... = ... | null | D.cs:337:13:337:15 | access to local variable msg | null | +| D.cs:337:13:337:23 | ... = ... | null | D.cs:337:19:337:23 | "foo" | null | +| D.cs:339:13:339:23 | ... = ... | non-null | D.cs:339:13:339:15 | access to local variable msg | non-null | +| D.cs:339:13:339:23 | ... = ... | non-null | D.cs:339:19:339:23 | "bar" | non-null | +| D.cs:339:13:339:23 | ... = ... | null | D.cs:339:13:339:15 | access to local variable msg | null | +| D.cs:339:13:339:23 | ... = ... | null | D.cs:339:19:339:23 | "bar" | null | | D.cs:341:13:341:23 | ... != ... | false | D.cs:341:13:341:15 | access to local variable msg | null | | D.cs:341:13:341:23 | ... != ... | true | D.cs:341:13:341:15 | access to local variable msg | non-null | | D.cs:343:13:343:27 | ... + ... | non-null | D.cs:343:13:343:15 | access to local variable msg | non-null | +| D.cs:343:13:343:27 | ... + ... | non-null | D.cs:343:20:343:27 | "foobar" | non-null | | D.cs:343:13:343:27 | ... + ... | null | D.cs:343:13:343:15 | access to local variable msg | null | +| D.cs:343:13:343:27 | ... += ... | non-null | D.cs:343:13:343:15 | access to local variable msg | non-null | +| D.cs:343:13:343:27 | ... += ... | null | D.cs:343:13:343:15 | access to local variable msg | null | +| D.cs:343:13:343:27 | ... = ... | non-null | D.cs:343:13:343:15 | access to local variable msg | non-null | +| D.cs:343:13:343:27 | ... = ... | non-null | D.cs:343:13:343:27 | ... + ... | non-null | +| D.cs:343:13:343:27 | ... = ... | null | D.cs:343:13:343:15 | access to local variable msg | null | +| D.cs:343:13:343:27 | ... = ... | null | D.cs:343:13:343:27 | ... + ... | null | | D.cs:344:33:344:35 | access to local variable msg | non-null | D.cs:343:13:343:27 | ... + ... | non-null | | D.cs:344:33:344:35 | access to local variable msg | null | D.cs:343:13:343:27 | ... + ... | null | +| D.cs:351:15:351:22 | Int32[] a = ... | non-null | D.cs:351:15:351:15 | access to local variable a | non-null | +| D.cs:351:15:351:22 | Int32[] a = ... | null | D.cs:351:15:351:15 | access to local variable a | null | +| D.cs:353:13:353:30 | ... = ... | non-null | D.cs:353:13:353:13 | access to local variable a | non-null | +| D.cs:353:13:353:30 | ... = ... | non-null | D.cs:353:17:353:30 | array creation of type Int32[] | non-null | +| D.cs:353:13:353:30 | ... = ... | null | D.cs:353:13:353:13 | access to local variable a | null | +| D.cs:353:13:353:30 | ... = ... | null | D.cs:353:17:353:30 | array creation of type Int32[] | null | +| D.cs:360:20:360:30 | String last = ... | non-null | D.cs:360:20:360:23 | access to local variable last | non-null | +| D.cs:360:20:360:30 | String last = ... | null | D.cs:360:20:360:23 | access to local variable last | null | +| D.cs:362:17:362:28 | ... = ... | non-null | D.cs:362:17:362:20 | access to local variable last | non-null | +| D.cs:362:17:362:28 | ... = ... | non-null | D.cs:362:24:362:28 | "abc" | non-null | +| D.cs:362:17:362:28 | ... = ... | null | D.cs:362:17:362:20 | access to local variable last | null | +| D.cs:362:17:362:28 | ... = ... | null | D.cs:362:24:362:28 | "abc" | null | +| D.cs:366:15:366:47 | Int32[] b = ... | non-null | D.cs:366:15:366:15 | access to local variable b | non-null | +| D.cs:366:15:366:47 | Int32[] b = ... | null | D.cs:366:15:366:15 | access to local variable b | null | | D.cs:367:13:367:56 | ... && ... | true | D.cs:367:13:367:21 | ... > ... | true | | D.cs:367:13:367:56 | ... && ... | true | D.cs:367:27:367:55 | ... \|\| ... | true | | D.cs:367:27:367:27 | access to local variable b | non-null | D.cs:366:19:366:47 | ... ? ... : ... | non-null | @@ -494,8 +956,18 @@ | D.cs:367:40:367:40 | access to local variable b | null | D.cs:366:19:366:47 | ... ? ... : ... | null | | D.cs:372:13:372:13 | access to local variable b | non-null | D.cs:366:19:366:47 | ... ? ... : ... | non-null | | D.cs:372:13:372:13 | access to local variable b | null | D.cs:366:19:366:47 | ... ? ... : ... | null | +| D.cs:378:19:378:28 | Exception ioe = ... | non-null | D.cs:378:19:378:21 | access to local variable ioe | non-null | +| D.cs:378:19:378:28 | Exception ioe = ... | null | D.cs:378:19:378:21 | access to local variable ioe | null | +| D.cs:380:13:380:35 | ... = ... | non-null | D.cs:380:13:380:15 | access to local variable ioe | non-null | +| D.cs:380:13:380:35 | ... = ... | non-null | D.cs:380:19:380:35 | object creation of type Exception | non-null | +| D.cs:380:13:380:35 | ... = ... | null | D.cs:380:13:380:15 | access to local variable ioe | null | +| D.cs:380:13:380:35 | ... = ... | null | D.cs:380:19:380:35 | object creation of type Exception | null | | D.cs:382:13:382:23 | ... != ... | false | D.cs:382:13:382:15 | access to local variable ioe | null | | D.cs:382:13:382:23 | ... != ... | true | D.cs:382:13:382:15 | access to local variable ioe | non-null | +| D.cs:383:13:383:19 | ... = ... | non-null | D.cs:383:13:383:15 | access to local variable ioe | non-null | +| D.cs:383:13:383:19 | ... = ... | non-null | D.cs:383:19:383:19 | access to parameter e | non-null | +| D.cs:383:13:383:19 | ... = ... | null | D.cs:383:13:383:15 | access to local variable ioe | null | +| D.cs:383:13:383:19 | ... = ... | null | D.cs:383:19:383:19 | access to parameter e | null | | D.cs:390:20:390:28 | ... == ... | false | D.cs:390:20:390:20 | access to parameter a | non-null | | D.cs:390:20:390:28 | ... == ... | true | D.cs:390:20:390:20 | access to parameter a | null | | D.cs:397:20:397:28 | ... == ... | false | D.cs:397:20:397:20 | access to parameter b | non-null | @@ -518,18 +990,38 @@ | D.cs:409:13:409:21 | ... != ... | true | D.cs:409:13:409:13 | access to parameter x | non-null | | D.cs:411:13:411:21 | ... != ... | false | D.cs:411:13:411:13 | access to parameter y | null | | D.cs:411:13:411:21 | ... != ... | true | D.cs:411:13:411:13 | access to parameter y | non-null | +| E.cs:9:18:9:26 | Int64[][] a2 = ... | non-null | E.cs:9:18:9:19 | access to local variable a2 | non-null | +| E.cs:9:18:9:26 | Int64[][] a2 = ... | null | E.cs:9:18:9:19 | access to local variable a2 | null | +| E.cs:10:13:10:54 | Boolean haveA2 = ... | false | E.cs:10:13:10:18 | access to local variable haveA2 | false | +| E.cs:10:13:10:54 | Boolean haveA2 = ... | true | E.cs:10:13:10:18 | access to local variable haveA2 | true | | E.cs:10:22:10:54 | ... && ... | true | E.cs:10:22:10:29 | ... < ... | true | | E.cs:10:22:10:54 | ... && ... | true | E.cs:10:34:10:54 | ... != ... | true | | E.cs:10:34:10:54 | ... != ... | false | E.cs:10:35:10:45 | ... = ... | null | | E.cs:10:34:10:54 | ... != ... | true | E.cs:10:35:10:45 | ... = ... | non-null | +| E.cs:10:35:10:45 | ... = ... | non-null | E.cs:10:35:10:36 | access to local variable a2 | non-null | +| E.cs:10:35:10:45 | ... = ... | non-null | E.cs:10:40:10:45 | access to array element | non-null | +| E.cs:10:35:10:45 | ... = ... | null | E.cs:10:35:10:36 | access to local variable a2 | null | +| E.cs:10:35:10:45 | ... = ... | null | E.cs:10:40:10:45 | access to array element | null | +| E.cs:11:16:11:24 | Int64[] a3 = ... | non-null | E.cs:11:16:11:17 | access to local variable a3 | non-null | +| E.cs:11:16:11:24 | Int64[] a3 = ... | null | E.cs:11:16:11:17 | access to local variable a3 | null | +| E.cs:12:13:12:52 | Boolean haveA3 = ... | false | E.cs:12:13:12:18 | access to local variable haveA3 | false | +| E.cs:12:13:12:52 | Boolean haveA3 = ... | true | E.cs:12:13:12:18 | access to local variable haveA3 | true | | E.cs:12:22:12:27 | access to local variable haveA2 | false | E.cs:10:22:10:54 | ... && ... | false | | E.cs:12:22:12:27 | access to local variable haveA2 | true | E.cs:10:22:10:54 | ... && ... | true | | E.cs:12:22:12:52 | ... && ... | true | E.cs:12:22:12:27 | access to local variable haveA2 | true | | E.cs:12:22:12:52 | ... && ... | true | E.cs:12:32:12:52 | ... != ... | true | | E.cs:12:32:12:52 | ... != ... | false | E.cs:12:33:12:43 | ... = ... | null | | E.cs:12:32:12:52 | ... != ... | true | E.cs:12:33:12:43 | ... = ... | non-null | +| E.cs:12:33:12:43 | ... = ... | non-null | E.cs:12:33:12:34 | access to local variable a3 | non-null | +| E.cs:12:33:12:43 | ... = ... | non-null | E.cs:12:38:12:43 | access to array element | non-null | +| E.cs:12:33:12:43 | ... = ... | null | E.cs:12:33:12:34 | access to local variable a3 | null | +| E.cs:12:33:12:43 | ... = ... | null | E.cs:12:38:12:43 | access to array element | null | | E.cs:13:13:13:18 | access to local variable haveA3 | false | E.cs:12:22:12:52 | ... && ... | false | | E.cs:13:13:13:18 | access to local variable haveA3 | true | E.cs:12:22:12:52 | ... && ... | true | +| E.cs:19:13:19:30 | String s1 = ... | non-null | E.cs:19:13:19:14 | access to local variable s1 | non-null | +| E.cs:19:13:19:30 | String s1 = ... | null | E.cs:19:13:19:14 | access to local variable s1 | null | +| E.cs:20:13:20:41 | String s2 = ... | non-null | E.cs:20:13:20:14 | access to local variable s2 | non-null | +| E.cs:20:13:20:41 | String s2 = ... | null | E.cs:20:13:20:14 | access to local variable s2 | null | | E.cs:20:19:20:20 | access to local variable s1 | non-null | E.cs:19:18:19:30 | ... ? ... : ... | non-null | | E.cs:20:19:20:20 | access to local variable s1 | null | E.cs:19:18:19:30 | ... ? ... : ... | null | | E.cs:20:19:20:28 | ... == ... | false | E.cs:20:19:20:20 | access to local variable s1 | non-null | @@ -538,16 +1030,50 @@ | E.cs:21:13:21:14 | access to local variable s2 | null | E.cs:20:18:20:41 | ... ? ... : ... | null | | E.cs:21:13:21:22 | ... == ... | false | E.cs:21:13:21:14 | access to local variable s2 | non-null | | E.cs:21:13:21:22 | ... == ... | true | E.cs:21:13:21:14 | access to local variable s2 | null | +| E.cs:23:13:23:30 | ... = ... | non-null | E.cs:23:13:23:14 | access to local variable s1 | non-null | +| E.cs:23:13:23:30 | ... = ... | non-null | E.cs:23:18:23:30 | ... ? ... : ... | non-null | +| E.cs:23:13:23:30 | ... = ... | null | E.cs:23:13:23:14 | access to local variable s1 | null | +| E.cs:23:13:23:30 | ... = ... | null | E.cs:23:18:23:30 | ... ? ... : ... | null | +| E.cs:24:13:24:41 | ... = ... | non-null | E.cs:24:13:24:14 | access to local variable s2 | non-null | +| E.cs:24:13:24:41 | ... = ... | non-null | E.cs:24:18:24:41 | ... ? ... : ... | non-null | +| E.cs:24:13:24:41 | ... = ... | null | E.cs:24:13:24:14 | access to local variable s2 | null | +| E.cs:24:13:24:41 | ... = ... | null | E.cs:24:18:24:41 | ... ? ... : ... | null | | E.cs:24:19:24:20 | access to local variable s1 | non-null | E.cs:23:18:23:30 | ... ? ... : ... | non-null | | E.cs:24:19:24:20 | access to local variable s1 | null | E.cs:23:18:23:30 | ... ? ... : ... | null | | E.cs:24:19:24:28 | ... == ... | false | E.cs:24:19:24:20 | access to local variable s1 | non-null | | E.cs:24:19:24:28 | ... == ... | true | E.cs:24:19:24:20 | access to local variable s1 | null | | E.cs:26:13:26:22 | ... != ... | false | E.cs:26:13:26:14 | access to local variable s2 | null | | E.cs:26:13:26:22 | ... != ... | true | E.cs:26:13:26:14 | access to local variable s2 | non-null | +| E.cs:32:16:32:26 | String last = ... | non-null | E.cs:32:16:32:19 | access to local variable last | non-null | +| E.cs:32:16:32:26 | String last = ... | null | E.cs:32:16:32:19 | access to local variable last | null | +| E.cs:34:13:34:20 | ... = ... | non-null | E.cs:34:13:34:16 | access to local variable last | non-null | +| E.cs:34:13:34:20 | ... = ... | non-null | E.cs:34:20:34:20 | access to local variable s | non-null | +| E.cs:34:13:34:20 | ... = ... | null | E.cs:34:13:34:16 | access to local variable last | null | +| E.cs:34:13:34:20 | ... = ... | null | E.cs:34:20:34:20 | access to local variable s | null | +| E.cs:37:9:37:19 | ... = ... | non-null | E.cs:37:9:37:12 | access to local variable last | non-null | +| E.cs:37:9:37:19 | ... = ... | non-null | E.cs:37:16:37:19 | null | non-null | +| E.cs:37:9:37:19 | ... = ... | null | E.cs:37:9:37:12 | access to local variable last | null | +| E.cs:37:9:37:19 | ... = ... | null | E.cs:37:16:37:19 | null | null | +| E.cs:41:17:41:24 | ... = ... | non-null | E.cs:41:17:41:20 | access to local variable last | non-null | +| E.cs:41:17:41:24 | ... = ... | non-null | E.cs:41:24:41:24 | access to local variable s | non-null | +| E.cs:41:17:41:24 | ... = ... | null | E.cs:41:17:41:20 | access to local variable last | null | +| E.cs:41:17:41:24 | ... = ... | null | E.cs:41:24:41:24 | access to local variable s | null | +| E.cs:50:13:50:45 | List> result = ... | non-null | E.cs:50:13:50:18 | access to local variable result | non-null | +| E.cs:50:13:50:45 | List> result = ... | null | E.cs:50:13:50:18 | access to local variable result | null | +| E.cs:51:22:51:33 | List slice = ... | non-null | E.cs:51:22:51:26 | access to local variable slice | non-null | +| E.cs:51:22:51:33 | List slice = ... | null | E.cs:51:22:51:26 | access to local variable slice | null | +| E.cs:52:13:52:39 | IEnumerator iter = ... | non-null | E.cs:52:13:52:16 | access to local variable iter | non-null | +| E.cs:52:13:52:39 | IEnumerator iter = ... | null | E.cs:52:13:52:16 | access to local variable iter | null | | E.cs:53:16:53:19 | access to local variable iter | non-null | E.cs:52:20:52:39 | call to method GetEnumerator | non-null | | E.cs:53:16:53:19 | access to local variable iter | null | E.cs:52:20:52:39 | call to method GetEnumerator | null | +| E.cs:55:17:55:34 | String str = ... | non-null | E.cs:55:17:55:19 | access to local variable str | non-null | +| E.cs:55:17:55:34 | String str = ... | null | E.cs:55:17:55:19 | access to local variable str | null | | E.cs:55:23:55:26 | access to local variable iter | non-null | E.cs:52:20:52:39 | call to method GetEnumerator | non-null | | E.cs:55:23:55:26 | access to local variable iter | null | E.cs:52:20:52:39 | call to method GetEnumerator | null | +| E.cs:58:17:58:42 | ... = ... | non-null | E.cs:58:17:58:21 | access to local variable slice | non-null | +| E.cs:58:17:58:42 | ... = ... | non-null | E.cs:58:25:58:42 | object creation of type List | non-null | +| E.cs:58:17:58:42 | ... = ... | null | E.cs:58:17:58:21 | access to local variable slice | null | +| E.cs:58:17:58:42 | ... = ... | null | E.cs:58:25:58:42 | object creation of type List | null | | E.cs:59:17:59:22 | access to local variable result | non-null | E.cs:50:22:50:45 | object creation of type List> | non-null | | E.cs:59:17:59:22 | access to local variable result | null | E.cs:50:22:50:45 | object creation of type List> | null | | E.cs:59:28:59:32 | access to local variable slice | non-null | E.cs:58:25:58:42 | object creation of type List | non-null | @@ -564,16 +1090,40 @@ | E.cs:85:18:85:29 | ... != ... | true | E.cs:85:18:85:21 | access to parameter vals | non-null | | E.cs:85:18:85:35 | ... && ... | true | E.cs:85:18:85:29 | ... != ... | true | | E.cs:85:18:85:35 | ... && ... | true | E.cs:85:34:85:35 | access to parameter b2 | true | +| E.cs:107:15:107:25 | Int32[] arr2 = ... | non-null | E.cs:107:15:107:18 | access to local variable arr2 | non-null | +| E.cs:107:15:107:25 | Int32[] arr2 = ... | null | E.cs:107:15:107:18 | access to local variable arr2 | null | +| E.cs:109:13:109:39 | ... = ... | non-null | E.cs:109:13:109:16 | access to local variable arr2 | non-null | +| E.cs:109:13:109:39 | ... = ... | non-null | E.cs:109:20:109:39 | array creation of type Int32[] | non-null | +| E.cs:109:13:109:39 | ... = ... | null | E.cs:109:13:109:16 | access to local variable arr2 | null | +| E.cs:109:13:109:39 | ... = ... | null | E.cs:109:20:109:39 | array creation of type Int32[] | null | +| E.cs:117:14:117:25 | Boolean stop = ... | false | E.cs:117:14:117:17 | access to local variable stop | false | +| E.cs:117:14:117:25 | Boolean stop = ... | true | E.cs:117:14:117:17 | access to local variable stop | true | +| E.cs:119:13:119:30 | Object obj = ... | non-null | E.cs:119:13:119:15 | access to local variable obj | non-null | +| E.cs:119:13:119:30 | Object obj = ... | null | E.cs:119:13:119:15 | access to local variable obj | null | | E.cs:120:16:120:20 | !... | false | E.cs:120:17:120:20 | access to local variable stop | true | | E.cs:120:16:120:20 | !... | true | E.cs:120:17:120:20 | access to local variable stop | false | | E.cs:123:20:123:24 | !... | false | E.cs:123:21:123:24 | access to local variable stop | true | | E.cs:123:20:123:24 | !... | true | E.cs:123:21:123:24 | access to local variable stop | false | | E.cs:123:20:123:35 | ... && ... | true | E.cs:123:20:123:24 | !... | true | | E.cs:123:20:123:35 | ... && ... | true | E.cs:123:29:123:35 | ... < ... | true | +| E.cs:130:21:130:33 | ... = ... | false | E.cs:130:21:130:24 | access to local variable stop | false | +| E.cs:130:21:130:33 | ... = ... | false | E.cs:130:28:130:33 | ... >= ... | false | +| E.cs:130:21:130:33 | ... = ... | true | E.cs:130:21:130:24 | access to local variable stop | true | +| E.cs:130:21:130:33 | ... = ... | true | E.cs:130:28:130:33 | ... >= ... | true | | E.cs:131:25:131:29 | !... | false | E.cs:131:26:131:29 | access to local variable stop | true | | E.cs:131:25:131:29 | !... | true | E.cs:131:26:131:29 | access to local variable stop | false | | E.cs:131:26:131:29 | access to local variable stop | false | E.cs:130:28:130:33 | ... >= ... | false | | E.cs:131:26:131:29 | access to local variable stop | true | E.cs:130:28:130:33 | ... >= ... | true | +| E.cs:133:25:133:42 | ... = ... | non-null | E.cs:133:25:133:27 | access to local variable obj | non-null | +| E.cs:133:25:133:42 | ... = ... | non-null | E.cs:133:31:133:42 | object creation of type Object | non-null | +| E.cs:133:25:133:42 | ... = ... | null | E.cs:133:25:133:27 | access to local variable obj | null | +| E.cs:133:25:133:42 | ... = ... | null | E.cs:133:31:133:42 | object creation of type Object | null | +| E.cs:137:25:137:34 | ... = ... | non-null | E.cs:137:25:137:27 | access to local variable obj | non-null | +| E.cs:137:25:137:34 | ... = ... | non-null | E.cs:137:31:137:34 | null | non-null | +| E.cs:137:25:137:34 | ... = ... | null | E.cs:137:25:137:27 | access to local variable obj | null | +| E.cs:137:25:137:34 | ... = ... | null | E.cs:137:31:137:34 | null | null | +| E.cs:152:16:152:26 | Object obj2 = ... | non-null | E.cs:152:16:152:19 | access to local variable obj2 | non-null | +| E.cs:152:16:152:26 | Object obj2 = ... | null | E.cs:152:16:152:19 | access to local variable obj2 | null | | E.cs:153:13:153:16 | access to local variable obj2 | non-null | E.cs:152:23:152:26 | access to parameter obj1 | non-null | | E.cs:153:13:153:16 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | | E.cs:153:13:153:24 | ... != ... | false | E.cs:153:13:153:16 | access to local variable obj2 | null | @@ -584,33 +1134,73 @@ | E.cs:153:29:153:32 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | | E.cs:155:13:155:16 | access to local variable obj2 | non-null | E.cs:152:23:152:26 | access to parameter obj1 | non-null | | E.cs:155:13:155:16 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | +| E.cs:156:13:156:23 | ... = ... | false | E.cs:156:13:156:16 | access to parameter cond | false | +| E.cs:156:13:156:23 | ... = ... | true | E.cs:156:13:156:16 | access to parameter cond | true | | E.cs:159:13:159:16 | access to local variable obj2 | non-null | E.cs:152:23:152:26 | access to parameter obj1 | non-null | | E.cs:159:13:159:16 | access to local variable obj2 | null | E.cs:152:23:152:26 | access to parameter obj1 | null | | E.cs:164:17:164:25 | ... == ... | false | E.cs:164:17:164:17 | access to parameter a | non-null | | E.cs:164:17:164:25 | ... == ... | true | E.cs:164:17:164:17 | access to parameter a | null | +| E.cs:169:17:169:30 | ... = ... | non-null | E.cs:169:17:169:17 | access to parameter a | non-null | +| E.cs:169:17:169:30 | ... = ... | non-null | E.cs:169:21:169:30 | array creation of type Int32[] | non-null | +| E.cs:169:17:169:30 | ... = ... | null | E.cs:169:17:169:17 | access to parameter a | null | +| E.cs:169:17:169:30 | ... = ... | null | E.cs:169:21:169:30 | array creation of type Int32[] | null | +| E.cs:175:14:175:42 | Boolean b2 = ... | false | E.cs:175:14:175:15 | access to local variable b2 | false | +| E.cs:175:14:175:42 | Boolean b2 = ... | true | E.cs:175:14:175:15 | access to local variable b2 | true | | E.cs:175:19:175:29 | ... == ... | false | E.cs:175:19:175:21 | access to parameter obj | non-null | | E.cs:175:19:175:29 | ... == ... | true | E.cs:175:19:175:21 | access to parameter obj | null | | E.cs:175:19:175:42 | ... ? ... : ... | true | E.cs:175:19:175:29 | ... == ... | false | | E.cs:175:19:175:42 | ... ? ... : ... | true | E.cs:175:41:175:42 | access to parameter b1 | true | +| E.cs:176:13:176:14 | (...) ... | non-null | E.cs:176:13:176:14 | access to local variable b2 | non-null | +| E.cs:176:13:176:14 | (...) ... | null | E.cs:176:13:176:14 | access to local variable b2 | null | | E.cs:176:13:176:14 | access to local variable b2 | false | E.cs:175:19:175:42 | ... ? ... : ... | false | | E.cs:176:13:176:14 | access to local variable b2 | true | E.cs:175:19:175:42 | ... ? ... : ... | true | | E.cs:176:13:176:22 | ... == ... | false | E.cs:176:13:176:14 | (...) ... | non-null | | E.cs:176:13:176:22 | ... == ... | true | E.cs:176:13:176:14 | (...) ... | null | | E.cs:180:13:180:23 | ... == ... | false | E.cs:180:13:180:15 | access to parameter obj | non-null | | E.cs:180:13:180:23 | ... == ... | true | E.cs:180:13:180:15 | access to parameter obj | null | +| E.cs:182:13:182:21 | ... = ... | false | E.cs:182:13:182:14 | access to parameter b1 | false | +| E.cs:182:13:182:21 | ... = ... | true | E.cs:182:13:182:14 | access to parameter b1 | true | +| E.cs:184:13:184:14 | (...) ... | non-null | E.cs:184:13:184:14 | access to parameter b1 | non-null | +| E.cs:184:13:184:14 | (...) ... | null | E.cs:184:13:184:14 | access to parameter b1 | null | | E.cs:184:13:184:22 | ... == ... | false | E.cs:184:13:184:14 | (...) ... | non-null | | E.cs:184:13:184:22 | ... == ... | true | E.cs:184:13:184:14 | (...) ... | null | +| E.cs:193:13:193:29 | String s = ... | non-null | E.cs:193:13:193:13 | access to local variable s | non-null | +| E.cs:193:13:193:29 | String s = ... | null | E.cs:193:13:193:13 | access to local variable s | null | +| E.cs:193:19:193:29 | call to method ToString | non-null | E.cs:193:17:193:17 | access to parameter o | non-null | +| E.cs:198:13:198:29 | String o = ... | non-null | E.cs:198:13:198:13 | access to local variable o | non-null | +| E.cs:198:13:198:29 | String o = ... | null | E.cs:198:13:198:13 | access to local variable o | null | | E.cs:199:9:199:9 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | | E.cs:199:9:199:9 | access to local variable o | null | E.cs:198:17:198:29 | ... ? ... : ... | null | | E.cs:201:11:201:11 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | | E.cs:201:11:201:11 | access to local variable o | null | E.cs:198:17:198:29 | ... ? ... : ... | null | | E.cs:203:11:203:11 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | | E.cs:203:11:203:11 | access to local variable o | null | E.cs:198:17:198:29 | ... ? ... : ... | null | +| E.cs:208:13:208:23 | ... is ... | false | E.cs:208:13:208:13 | access to parameter s | null | | E.cs:208:13:208:23 | ... is ... | true | E.cs:208:13:208:13 | access to parameter s | non-null | +| E.cs:215:13:215:18 | String x = ... | non-null | E.cs:215:13:215:13 | access to local variable x | non-null | +| E.cs:215:13:215:18 | String x = ... | null | E.cs:215:13:215:13 | access to local variable x | null | +| E.cs:217:13:217:20 | ... = ... | non-null | E.cs:217:13:217:13 | access to local variable x | non-null | +| E.cs:217:13:217:20 | ... = ... | non-null | E.cs:217:17:217:20 | null | non-null | +| E.cs:217:13:217:20 | ... = ... | null | E.cs:217:13:217:13 | access to local variable x | null | +| E.cs:217:13:217:20 | ... = ... | null | E.cs:217:17:217:20 | null | null | +| E.cs:225:13:225:18 | String x = ... | non-null | E.cs:225:13:225:13 | access to local variable x | non-null | +| E.cs:225:13:225:18 | String x = ... | null | E.cs:225:13:225:13 | access to local variable x | null | +| E.cs:227:13:227:20 | ... = ... | non-null | E.cs:227:13:227:13 | access to local variable x | non-null | +| E.cs:227:13:227:20 | ... = ... | non-null | E.cs:227:17:227:20 | null | non-null | +| E.cs:227:13:227:20 | ... = ... | null | E.cs:227:13:227:13 | access to local variable x | null | +| E.cs:227:13:227:20 | ... = ... | null | E.cs:227:17:227:20 | null | null | +| E.cs:245:13:245:22 | access to property HasValue | false | E.cs:245:13:245:13 | access to parameter i | null | +| E.cs:245:13:245:22 | access to property HasValue | true | E.cs:245:13:245:13 | access to parameter i | non-null | | E.cs:252:13:252:21 | ... != ... | false | E.cs:252:13:252:13 | access to parameter i | null | | E.cs:252:13:252:21 | ... != ... | true | E.cs:252:13:252:13 | access to parameter i | non-null | | E.cs:259:13:259:21 | ... == ... | false | E.cs:259:13:259:13 | access to parameter i | non-null | | E.cs:259:13:259:21 | ... == ... | true | E.cs:259:13:259:13 | access to parameter i | null | +| E.cs:260:13:260:17 | ... = ... | non-null | E.cs:260:13:260:13 | access to parameter i | non-null | +| E.cs:260:13:260:17 | ... = ... | non-null | E.cs:260:17:260:17 | (...) ... | non-null | +| E.cs:260:13:260:17 | ... = ... | null | E.cs:260:13:260:13 | access to parameter i | null | +| E.cs:260:13:260:17 | ... = ... | null | E.cs:260:17:260:17 | (...) ... | null | +| Forwarding.cs:7:16:7:23 | String s = ... | non-null | Forwarding.cs:7:16:7:16 | access to local variable s | non-null | +| Forwarding.cs:7:16:7:23 | String s = ... | null | Forwarding.cs:7:16:7:16 | access to local variable s | null | | Forwarding.cs:9:13:9:30 | !... | false | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | true | | Forwarding.cs:9:13:9:30 | !... | true | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | false | | Forwarding.cs:9:14:9:14 | access to local variable s | non-null | Forwarding.cs:7:20:7:23 | null | non-null | @@ -655,6 +1245,8 @@ | Forwarding.cs:45:30:45:61 | !... | false | Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | true | | Forwarding.cs:45:30:45:61 | !... | true | Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | false | | Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | false | Forwarding.cs:45:52:45:60 | (...) ... | non-null | +| Forwarding.cs:45:52:45:60 | (...) ... | non-null | Forwarding.cs:45:60:45:60 | access to parameter o | non-null | +| Forwarding.cs:45:52:45:60 | (...) ... | null | Forwarding.cs:45:60:45:60 | access to parameter o | null | | Forwarding.cs:45:65:45:75 | !... | false | Forwarding.cs:45:66:45:75 | call to method IsNull | true | | Forwarding.cs:45:65:45:75 | !... | true | Forwarding.cs:45:66:45:75 | call to method IsNull | false | | Forwarding.cs:45:66:45:75 | call to method IsNull | false | Forwarding.cs:45:66:45:66 | access to parameter o | non-null | @@ -663,6 +1255,8 @@ | Forwarding.cs:52:20:52:51 | !... | false | Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | true | | Forwarding.cs:52:20:52:51 | !... | true | Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | false | | Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | false | Forwarding.cs:52:42:52:50 | (...) ... | non-null | +| Forwarding.cs:52:42:52:50 | (...) ... | non-null | Forwarding.cs:52:50:52:50 | access to parameter o | non-null | +| Forwarding.cs:52:42:52:50 | (...) ... | null | Forwarding.cs:52:50:52:50 | access to parameter o | null | | Forwarding.cs:59:13:59:21 | ... == ... | false | Forwarding.cs:59:13:59:13 | access to parameter o | non-null | | Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:13:59:13 | access to parameter o | null | | Forwarding.cs:68:16:68:38 | call to method IsNullOrEmpty | false | Forwarding.cs:68:37:68:37 | access to parameter s | non-null | @@ -673,6 +1267,8 @@ | Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:32:78:32 | access to parameter o | null | | Forwarding.cs:83:16:83:24 | ... != ... | false | Forwarding.cs:83:16:83:16 | access to parameter o | null | | Forwarding.cs:83:16:83:24 | ... != ... | true | Forwarding.cs:83:16:83:16 | access to parameter o | non-null | +| GuardedString.cs:7:16:7:32 | String s = ... | non-null | GuardedString.cs:7:16:7:16 | access to local variable s | non-null | +| GuardedString.cs:7:16:7:32 | String s = ... | null | GuardedString.cs:7:16:7:16 | access to local variable s | null | | GuardedString.cs:9:13:9:36 | !... | false | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | true | | GuardedString.cs:9:13:9:36 | !... | true | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | GuardedString.cs:9:35:9:35 | access to local variable s | non-null | @@ -731,17 +1327,73 @@ | GuardedString.cs:35:31:35:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:37:31:37:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:37:31:37:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| NullAlwaysBad.cs:9:17:9:25 | ... != ... | false | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | null | +| NullAlwaysBad.cs:9:17:9:25 | ... != ... | true | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | non-null | +| NullAlwaysBad.cs:9:17:9:41 | ... \|\| ... | false | NullAlwaysBad.cs:9:17:9:25 | ... != ... | false | +| NullAlwaysBad.cs:9:17:9:41 | ... \|\| ... | false | NullAlwaysBad.cs:9:30:9:41 | ... > ... | false | +| NullAlwaysGood.cs:9:17:9:25 | ... != ... | false | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | null | +| NullAlwaysGood.cs:9:17:9:25 | ... != ... | true | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | non-null | +| NullAlwaysGood.cs:9:17:9:41 | ... && ... | true | NullAlwaysGood.cs:9:17:9:25 | ... != ... | true | +| NullAlwaysGood.cs:9:17:9:41 | ... && ... | true | NullAlwaysGood.cs:9:30:9:41 | ... > ... | true | +| NullMaybeGood.cs:9:17:9:25 | ... != ... | false | NullMaybeGood.cs:9:17:9:17 | access to parameter o | null | +| NullMaybeGood.cs:9:17:9:25 | ... != ... | true | NullMaybeGood.cs:9:17:9:17 | access to parameter o | non-null | +| StringConcatenation.cs:7:16:7:23 | String s = ... | non-null | StringConcatenation.cs:7:16:7:16 | access to local variable s | non-null | +| StringConcatenation.cs:7:16:7:23 | String s = ... | null | StringConcatenation.cs:7:16:7:16 | access to local variable s | null | | StringConcatenation.cs:8:9:8:9 | access to local variable s | non-null | StringConcatenation.cs:7:20:7:23 | null | non-null | | StringConcatenation.cs:8:9:8:9 | access to local variable s | null | StringConcatenation.cs:7:20:7:23 | null | null | | StringConcatenation.cs:8:9:8:18 | ... + ... | non-null | StringConcatenation.cs:8:9:8:9 | access to local variable s | non-null | +| StringConcatenation.cs:8:9:8:18 | ... + ... | non-null | StringConcatenation.cs:8:14:8:18 | "abc" | non-null | | StringConcatenation.cs:8:9:8:18 | ... + ... | null | StringConcatenation.cs:8:9:8:9 | access to local variable s | null | +| StringConcatenation.cs:8:9:8:18 | ... += ... | non-null | StringConcatenation.cs:8:9:8:9 | access to local variable s | non-null | +| StringConcatenation.cs:8:9:8:18 | ... += ... | null | StringConcatenation.cs:8:9:8:9 | access to local variable s | null | +| StringConcatenation.cs:8:9:8:18 | ... = ... | non-null | StringConcatenation.cs:8:9:8:9 | access to local variable s | non-null | +| StringConcatenation.cs:8:9:8:18 | ... = ... | non-null | StringConcatenation.cs:8:9:8:18 | ... + ... | non-null | +| StringConcatenation.cs:8:9:8:18 | ... = ... | null | StringConcatenation.cs:8:9:8:9 | access to local variable s | null | +| StringConcatenation.cs:8:9:8:18 | ... = ... | null | StringConcatenation.cs:8:9:8:18 | ... + ... | null | +| StringConcatenation.cs:9:9:9:20 | ... = ... | non-null | StringConcatenation.cs:9:9:9:9 | access to local variable s | non-null | +| StringConcatenation.cs:9:9:9:20 | ... = ... | non-null | StringConcatenation.cs:9:13:9:20 | call to method Trim | non-null | +| StringConcatenation.cs:9:9:9:20 | ... = ... | null | StringConcatenation.cs:9:9:9:9 | access to local variable s | null | +| StringConcatenation.cs:9:9:9:20 | ... = ... | null | StringConcatenation.cs:9:13:9:20 | call to method Trim | null | | StringConcatenation.cs:9:13:9:13 | access to local variable s | non-null | StringConcatenation.cs:8:9:8:18 | ... + ... | non-null | | StringConcatenation.cs:9:13:9:13 | access to local variable s | null | StringConcatenation.cs:8:9:8:18 | ... + ... | null | +| StringConcatenation.cs:14:16:14:23 | String s = ... | non-null | StringConcatenation.cs:14:16:14:16 | access to local variable s | non-null | +| StringConcatenation.cs:14:16:14:23 | String s = ... | null | StringConcatenation.cs:14:16:14:16 | access to local variable s | null | | StringConcatenation.cs:15:16:15:22 | ... != ... | false | StringConcatenation.cs:15:16:15:16 | access to local variable s | non-null | +| StringConcatenation.cs:16:13:16:24 | ... = ... | non-null | StringConcatenation.cs:16:13:16:13 | access to local variable s | non-null | +| StringConcatenation.cs:16:13:16:24 | ... = ... | non-null | StringConcatenation.cs:16:17:16:24 | call to method Trim | non-null | +| StringConcatenation.cs:16:13:16:24 | ... = ... | null | StringConcatenation.cs:16:13:16:13 | access to local variable s | null | +| StringConcatenation.cs:16:13:16:24 | ... = ... | null | StringConcatenation.cs:16:17:16:24 | call to method Trim | null | +| StringConcatenation.cs:21:16:21:23 | String s = ... | non-null | StringConcatenation.cs:21:16:21:16 | access to local variable s | non-null | +| StringConcatenation.cs:21:16:21:23 | String s = ... | null | StringConcatenation.cs:21:16:21:16 | access to local variable s | null | | StringConcatenation.cs:22:16:22:22 | ... != ... | false | StringConcatenation.cs:22:16:22:16 | access to local variable s | non-null | | StringConcatenation.cs:23:13:23:22 | ... + ... | non-null | StringConcatenation.cs:23:13:23:13 | access to local variable s | non-null | +| StringConcatenation.cs:23:13:23:22 | ... + ... | non-null | StringConcatenation.cs:23:18:23:22 | "abc" | non-null | | StringConcatenation.cs:23:13:23:22 | ... + ... | null | StringConcatenation.cs:23:13:23:13 | access to local variable s | null | +| StringConcatenation.cs:23:13:23:22 | ... += ... | non-null | StringConcatenation.cs:23:13:23:13 | access to local variable s | non-null | +| StringConcatenation.cs:23:13:23:22 | ... += ... | null | StringConcatenation.cs:23:13:23:13 | access to local variable s | null | +| StringConcatenation.cs:23:13:23:22 | ... = ... | non-null | StringConcatenation.cs:23:13:23:13 | access to local variable s | non-null | +| StringConcatenation.cs:23:13:23:22 | ... = ... | non-null | StringConcatenation.cs:23:13:23:22 | ... + ... | non-null | +| StringConcatenation.cs:23:13:23:22 | ... = ... | null | StringConcatenation.cs:23:13:23:13 | access to local variable s | null | +| StringConcatenation.cs:23:13:23:22 | ... = ... | null | StringConcatenation.cs:23:13:23:22 | ... + ... | null | +| StringConcatenation.cs:24:9:24:20 | ... = ... | non-null | StringConcatenation.cs:24:9:24:9 | access to local variable s | non-null | +| StringConcatenation.cs:24:9:24:20 | ... = ... | non-null | StringConcatenation.cs:24:13:24:20 | call to method Trim | non-null | +| StringConcatenation.cs:24:9:24:20 | ... = ... | null | StringConcatenation.cs:24:9:24:9 | access to local variable s | null | +| StringConcatenation.cs:24:9:24:20 | ... = ... | null | StringConcatenation.cs:24:13:24:20 | call to method Trim | null | +| StringConcatenation.cs:29:16:29:24 | String s = ... | non-null | StringConcatenation.cs:29:16:29:16 | access to local variable s | non-null | +| StringConcatenation.cs:29:16:29:24 | String s = ... | null | StringConcatenation.cs:29:16:29:16 | access to local variable s | null | | StringConcatenation.cs:30:9:30:9 | access to local variable s | non-null | StringConcatenation.cs:29:20:29:24 | "abc" | non-null | | StringConcatenation.cs:30:9:30:9 | access to local variable s | null | StringConcatenation.cs:29:20:29:24 | "abc" | null | +| StringConcatenation.cs:30:9:30:17 | ... + ... | non-null | StringConcatenation.cs:30:9:30:9 | access to local variable s | non-null | +| StringConcatenation.cs:30:9:30:17 | ... + ... | non-null | StringConcatenation.cs:30:14:30:17 | null | non-null | +| StringConcatenation.cs:30:9:30:17 | ... += ... | non-null | StringConcatenation.cs:30:9:30:9 | access to local variable s | non-null | +| StringConcatenation.cs:30:9:30:17 | ... += ... | null | StringConcatenation.cs:30:9:30:9 | access to local variable s | null | +| StringConcatenation.cs:30:9:30:17 | ... = ... | non-null | StringConcatenation.cs:30:9:30:9 | access to local variable s | non-null | +| StringConcatenation.cs:30:9:30:17 | ... = ... | non-null | StringConcatenation.cs:30:9:30:17 | ... + ... | non-null | +| StringConcatenation.cs:30:9:30:17 | ... = ... | null | StringConcatenation.cs:30:9:30:9 | access to local variable s | null | +| StringConcatenation.cs:30:9:30:17 | ... = ... | null | StringConcatenation.cs:30:9:30:17 | ... + ... | null | +| StringConcatenation.cs:31:9:31:20 | ... = ... | non-null | StringConcatenation.cs:31:9:31:9 | access to local variable s | non-null | +| StringConcatenation.cs:31:9:31:20 | ... = ... | non-null | StringConcatenation.cs:31:13:31:20 | call to method Trim | non-null | +| StringConcatenation.cs:31:9:31:20 | ... = ... | null | StringConcatenation.cs:31:9:31:9 | access to local variable s | null | +| StringConcatenation.cs:31:9:31:20 | ... = ... | null | StringConcatenation.cs:31:13:31:20 | call to method Trim | null | | StringConcatenation.cs:31:13:31:13 | access to local variable s | non-null | StringConcatenation.cs:30:9:30:17 | ... + ... | non-null | | StringConcatenation.cs:31:13:31:13 | access to local variable s | null | StringConcatenation.cs:30:9:30:17 | ... + ... | null | diff --git a/csharp/ql/test/query-tests/Nullness/NullAlways.expected b/csharp/ql/test/query-tests/Nullness/NullAlways.expected index 1b3e73aaeef..e2d358969c0 100644 --- a/csharp/ql/test/query-tests/Nullness/NullAlways.expected +++ b/csharp/ql/test/query-tests/Nullness/NullAlways.expected @@ -1,26 +1,38 @@ -| A.cs:8:15:8:32 | access to local variable synchronizedAlways | Variable $@ is always null here. | A.cs:7:16:7:33 | synchronizedAlways | synchronizedAlways | -| A.cs:17:9:17:17 | access to local variable arrayNull | Variable $@ is always null here. | A.cs:16:15:16:23 | arrayNull | arrayNull | -| A.cs:31:27:31:37 | access to local variable arrayAccess | Variable $@ is always null here. | A.cs:26:15:26:25 | arrayAccess | arrayAccess | -| A.cs:32:27:32:37 | access to local variable fieldAccess | Variable $@ is always null here. | A.cs:27:18:27:28 | fieldAccess | fieldAccess | -| A.cs:33:28:33:39 | access to local variable methodAccess | Variable $@ is always null here. | A.cs:28:16:28:27 | methodAccess | methodAccess | -| A.cs:34:27:34:36 | access to local variable methodCall | Variable $@ is always null here. | A.cs:29:16:29:25 | methodCall | methodCall | -| Assert.cs:15:27:15:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:23:27:23:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:31:27:31:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:47:27:47:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:51:27:51:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | -| B.cs:13:13:13:24 | access to local variable eqCallAlways | Variable $@ is always null here. | B.cs:7:11:7:22 | eqCallAlways | eqCallAlways | -| B.cs:24:13:24:25 | access to local variable neqCallAlways | Variable $@ is always null here. | B.cs:10:11:10:23 | neqCallAlways | neqCallAlways | -| C.cs:18:13:18:13 | access to local variable o | Variable $@ is always null here. | C.cs:10:16:10:16 | o | o | -| C.cs:42:9:42:9 | access to local variable s | Variable $@ is always null here. | C.cs:40:13:40:13 | s | s | -| C.cs:57:9:57:10 | access to local variable o2 | Variable $@ is always null here. | C.cs:55:13:55:14 | o2 | o2 | -| C.cs:163:13:163:13 | access to local variable s | Variable $@ is always null here. | C.cs:152:13:152:13 | s | s | -| C.cs:197:13:197:13 | access to local variable s | Variable $@ is always null here. | C.cs:186:13:186:13 | s | s | -| C.cs:219:13:219:13 | access to local variable s | Variable $@ is always null here. | C.cs:211:13:211:13 | s | s | -| C.cs:234:9:234:9 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s | -| C.cs:238:13:238:13 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s | -| C.cs:250:9:250:9 | access to local variable a | Variable $@ is always null here. | C.cs:249:15:249:15 | a | a | -| C.cs:261:9:261:10 | access to local variable ia | Variable $@ is always null here. | C.cs:258:15:258:16 | ia | ia | -| C.cs:262:20:262:21 | access to local variable sa | Variable $@ is always null here. | C.cs:259:18:259:19 | sa | sa | -| D.cs:385:13:385:15 | access to local variable ioe | Variable $@ is always null here. | D.cs:378:19:378:21 | ioe | ioe | -| E.cs:229:13:229:13 | access to local variable x | Variable $@ is always null here. | E.cs:225:13:225:13 | x | x | +| A.cs:8:15:8:32 | access to local variable synchronizedAlways | Variable '$@' is always null here. | A.cs:7:16:7:33 | synchronizedAlways | synchronizedAlways | +| A.cs:17:9:17:17 | access to local variable arrayNull | Variable '$@' is always null here. | A.cs:16:15:16:23 | arrayNull | arrayNull | +| A.cs:31:27:31:37 | access to local variable arrayAccess | Variable '$@' is always null here. | A.cs:26:15:26:25 | arrayAccess | arrayAccess | +| A.cs:32:27:32:37 | access to local variable fieldAccess | Variable '$@' is always null here. | A.cs:27:18:27:28 | fieldAccess | fieldAccess | +| A.cs:33:28:33:39 | access to local variable methodAccess | Variable '$@' is always null here. | A.cs:28:16:28:27 | methodAccess | methodAccess | +| A.cs:34:27:34:36 | access to local variable methodCall | Variable '$@' is always null here. | A.cs:29:16:29:25 | methodCall | methodCall | +| A.cs:50:9:50:14 | access to local variable varRef | Variable '$@' is always null here. | A.cs:48:16:48:21 | varRef | varRef | +| Assert.cs:15:27:15:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:23:27:23:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:31:27:31:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:47:27:47:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:51:27:51:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | +| B.cs:13:13:13:24 | access to local variable eqCallAlways | Variable '$@' is always null here. | B.cs:7:11:7:22 | eqCallAlways | eqCallAlways | +| B.cs:24:13:24:25 | access to local variable neqCallAlways | Variable '$@' is always null here. | B.cs:10:11:10:23 | neqCallAlways | neqCallAlways | +| C.cs:18:13:18:13 | access to local variable o | Variable '$@' is always null here. | C.cs:10:16:10:16 | o | o | +| C.cs:42:9:42:9 | access to local variable s | Variable '$@' is always null here. | C.cs:40:13:40:13 | s | s | +| C.cs:57:9:57:10 | access to local variable o2 | Variable '$@' is always null here. | C.cs:55:13:55:14 | o2 | o2 | +| C.cs:163:13:163:13 | access to local variable s | Variable '$@' is always null here. | C.cs:152:13:152:13 | s | s | +| C.cs:171:13:171:13 | access to local variable s | Variable '$@' is always null here. | C.cs:152:13:152:13 | s | s | +| C.cs:197:13:197:13 | access to local variable s | Variable '$@' is always null here. | C.cs:186:13:186:13 | s | s | +| C.cs:219:13:219:13 | access to local variable s | Variable '$@' is always null here. | C.cs:211:13:211:13 | s | s | +| C.cs:234:9:234:9 | access to local variable s | Variable '$@' is always null here. | C.cs:229:16:229:16 | s | s | +| C.cs:238:13:238:13 | access to local variable s | Variable '$@' is always null here. | C.cs:229:16:229:16 | s | s | +| C.cs:250:9:250:9 | access to local variable a | Variable '$@' is always null here. | C.cs:249:15:249:15 | a | a | +| C.cs:261:9:261:10 | access to local variable ia | Variable '$@' is always null here. | C.cs:258:15:258:16 | ia | ia | +| C.cs:262:20:262:21 | access to local variable sa | Variable '$@' is always null here. | C.cs:259:18:259:19 | sa | sa | +| D.cs:120:13:120:13 | access to local variable x | Variable '$@' is always null here. | D.cs:117:13:117:13 | x | x | +| D.cs:197:13:197:13 | access to local variable o | Variable '$@' is always null here. | D.cs:195:13:195:13 | o | o | +| D.cs:207:17:207:17 | access to local variable e | Variable '$@' is always null here. | D.cs:204:26:204:26 | e | e | +| D.cs:217:13:217:14 | access to local variable o3 | Variable '$@' is always null here. | D.cs:215:13:215:14 | o3 | o3 | +| D.cs:222:13:222:14 | access to local variable o4 | Variable '$@' is always null here. | D.cs:220:13:220:14 | o4 | o4 | +| D.cs:385:13:385:15 | access to local variable ioe | Variable '$@' is always null here. | D.cs:378:19:378:21 | ioe | ioe | +| E.cs:210:16:210:16 | access to parameter s | Variable '$@' is always null here. | E.cs:206:28:206:28 | s | s | +| E.cs:220:13:220:13 | access to local variable x | Variable '$@' is always null here. | E.cs:215:13:215:13 | x | x | +| E.cs:229:13:229:13 | access to local variable x | Variable '$@' is always null here. | E.cs:225:13:225:13 | x | x | +| Forwarding.cs:36:31:36:31 | access to local variable s | Variable '$@' is always null here. | Forwarding.cs:7:16:7:16 | s | s | +| Forwarding.cs:40:27:40:27 | access to local variable s | Variable '$@' is always null here. | Forwarding.cs:7:16:7:16 | s | s | +| NullAlwaysBad.cs:9:30:9:30 | access to parameter s | Variable '$@' is always null here. | NullAlwaysBad.cs:7:29:7:29 | s | s | diff --git a/csharp/ql/test/query-tests/Nullness/NullAlwaysBad.cs b/csharp/ql/test/query-tests/Nullness/NullAlwaysBad.cs new file mode 100644 index 00000000000..6f0d486f1c7 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/NullAlwaysBad.cs @@ -0,0 +1,13 @@ +using System; + +namespace NullAlways +{ + class Bad + { + void DoPrint(string s) + { + if (s != null || s.Length > 0) + Console.WriteLine(s); + } + } +} diff --git a/csharp/ql/test/query-tests/Nullness/NullAlwaysGood.cs b/csharp/ql/test/query-tests/Nullness/NullAlwaysGood.cs new file mode 100644 index 00000000000..14002b0b2f0 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/NullAlwaysGood.cs @@ -0,0 +1,13 @@ +using System; + +namespace NullAlways +{ + class Good + { + void DoPrint(string s) + { + if (s != null && s.Length > 0) + Console.WriteLine(s); + } + } +} diff --git a/csharp/ql/test/query-tests/Nullness/NullCheck.expected b/csharp/ql/test/query-tests/Nullness/NullCheck.expected index 99bc29da38f..5f42a85d2a8 100644 --- a/csharp/ql/test/query-tests/Nullness/NullCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/NullCheck.expected @@ -82,6 +82,7 @@ | D.cs:39:16:39:24 | ... == ... | D.cs:39:16:39:16 | access to parameter x | true | true | | D.cs:45:13:45:22 | ... != ... | D.cs:45:13:45:14 | access to local variable o1 | false | true | | D.cs:45:13:45:22 | ... != ... | D.cs:45:13:45:14 | access to local variable o1 | true | false | +| D.cs:48:13:48:24 | ... is ... | D.cs:48:13:48:14 | access to local variable o2 | false | true | | D.cs:48:13:48:24 | ... is ... | D.cs:48:13:48:14 | access to local variable o2 | true | false | | D.cs:51:13:51:44 | ... != ... | D.cs:51:14:51:35 | ... = ... | false | true | | D.cs:51:13:51:44 | ... != ... | D.cs:51:14:51:35 | ... = ... | true | false | @@ -184,7 +185,10 @@ | E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | true | true | | E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | non-null | false | | E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | null | true | +| E.cs:208:13:208:23 | ... is ... | E.cs:208:13:208:13 | access to parameter s | false | true | | E.cs:208:13:208:23 | ... is ... | E.cs:208:13:208:13 | access to parameter s | true | false | +| E.cs:245:13:245:22 | access to property HasValue | E.cs:245:13:245:13 | access to parameter i | false | true | +| E.cs:245:13:245:22 | access to property HasValue | E.cs:245:13:245:13 | access to parameter i | true | false | | E.cs:252:13:252:21 | ... != ... | E.cs:252:13:252:13 | access to parameter i | false | true | | E.cs:252:13:252:21 | ... != ... | E.cs:252:13:252:13 | access to parameter i | true | false | | E.cs:259:13:259:21 | ... == ... | E.cs:259:13:259:13 | access to parameter i | false | false | @@ -231,5 +235,11 @@ | GuardedString.cs:34:13:34:13 | access to local variable s | GuardedString.cs:34:13:34:13 | access to local variable s | non-null | false | | GuardedString.cs:34:13:34:13 | access to local variable s | GuardedString.cs:34:13:34:13 | access to local variable s | null | true | | GuardedString.cs:34:13:34:26 | ... != ... | GuardedString.cs:34:15:34:21 | access to property Length | false | false | +| NullAlwaysBad.cs:9:17:9:25 | ... != ... | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | false | true | +| NullAlwaysBad.cs:9:17:9:25 | ... != ... | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | true | false | +| NullAlwaysGood.cs:9:17:9:25 | ... != ... | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | false | true | +| NullAlwaysGood.cs:9:17:9:25 | ... != ... | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | true | false | +| NullMaybeGood.cs:9:17:9:25 | ... != ... | NullMaybeGood.cs:9:17:9:17 | access to parameter o | false | true | +| NullMaybeGood.cs:9:17:9:25 | ... != ... | NullMaybeGood.cs:9:17:9:17 | access to parameter o | true | false | | StringConcatenation.cs:15:16:15:22 | ... != ... | StringConcatenation.cs:15:16:15:16 | access to local variable s | false | false | | StringConcatenation.cs:22:16:22:22 | ... != ... | StringConcatenation.cs:22:16:22:16 | access to local variable s | false | false | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index e3929952d1e..f3bea25a6d1 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -1,45 +1,82 @@ -| C.cs:64:9:64:10 | access to local variable o1 | Variable $@ may be null here. | C.cs:62:13:62:14 | o1 | o1 | -| C.cs:68:9:68:10 | access to local variable o2 | Variable $@ may be null here. | C.cs:66:13:66:14 | o2 | o2 | -| C.cs:96:15:96:15 | access to local variable o | Variable $@ may be null here. | C.cs:95:13:95:13 | o | o | -| C.cs:171:13:171:13 | access to local variable s | Variable $@ may be null here. | C.cs:152:13:152:13 | s | s | -| C.cs:178:13:178:13 | access to local variable s | Variable $@ may be null here. | C.cs:152:13:152:13 | s | s | -| C.cs:204:13:204:13 | access to local variable s | Variable $@ may be null here. | C.cs:186:13:186:13 | s | s | -| C.cs:224:9:224:9 | access to local variable s | Variable $@ may be null here. | C.cs:211:13:211:13 | s | s | -| C.cs:243:13:243:13 | access to local variable s | Variable $@ may be null here. | C.cs:229:16:229:16 | s | s | -| D.cs:60:13:60:14 | access to local variable o4 | Variable $@ may be null here. | D.cs:54:13:54:14 | o4 | o4 | -| D.cs:62:13:62:14 | access to local variable o5 | Variable $@ may be null here. | D.cs:58:13:58:14 | o5 | o5 | -| D.cs:73:13:73:14 | access to local variable o7 | Variable $@ may be null here. | D.cs:68:13:68:14 | o7 | o7 | -| D.cs:78:13:78:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | -| D.cs:80:13:80:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | -| D.cs:82:13:82:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | -| D.cs:84:13:84:14 | access to local variable o8 | Variable $@ may be null here. | D.cs:75:13:75:14 | o8 | o8 | -| D.cs:91:13:91:14 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | -| D.cs:94:21:94:22 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | -| D.cs:98:21:98:22 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | -| D.cs:105:19:105:20 | access to local variable xs | Variable $@ may be null here. | D.cs:89:15:89:16 | xs | xs | -| D.cs:171:9:171:11 | access to local variable obj | Variable $@ may be null here. | D.cs:163:16:163:18 | obj | obj | -| D.cs:245:13:245:13 | access to local variable o | Variable $@ may be null here. | D.cs:228:16:228:16 | o | o | -| D.cs:247:13:247:13 | access to local variable o | Variable $@ may be null here. | D.cs:228:16:228:16 | o | o | -| D.cs:253:13:253:14 | access to local variable o2 | Variable $@ may be null here. | D.cs:249:13:249:14 | o2 | o2 | -| D.cs:267:13:267:13 | access to local variable o | Variable $@ may be null here. | D.cs:258:16:258:16 | o | o | -| D.cs:291:13:291:13 | access to local variable o | Variable $@ may be null here. | D.cs:258:16:258:16 | o | o | -| D.cs:294:13:294:13 | access to local variable o | Variable $@ may be null here. | D.cs:258:16:258:16 | o | o | -| D.cs:300:17:300:20 | access to local variable prev | Variable $@ may be null here. | D.cs:296:16:296:19 | prev | prev | -| D.cs:313:17:313:17 | access to local variable s | Variable $@ may be null here. | D.cs:304:16:304:16 | s | s | -| D.cs:324:9:324:9 | access to local variable r | Variable $@ may be null here. | D.cs:316:16:316:16 | r | r | -| D.cs:356:13:356:13 | access to local variable a | Variable $@ may be null here. | D.cs:351:15:351:15 | a | a | -| D.cs:363:13:363:16 | access to local variable last | Variable $@ may be null here. | D.cs:360:20:360:23 | last | last | -| D.cs:372:13:372:13 | access to local variable b | Variable $@ may be null here. | D.cs:366:15:366:15 | b | b | -| E.cs:12:38:12:39 | access to local variable a2 | Variable $@ may be null here. | E.cs:9:18:9:19 | a2 | a2 | -| E.cs:14:13:14:14 | access to local variable a3 | Variable $@ may be null here. | E.cs:11:16:11:17 | a3 | a3 | -| E.cs:27:13:27:14 | access to local variable s1 | Variable $@ may be null here. | E.cs:19:13:19:14 | s1 | s1 | -| E.cs:35:9:35:12 | access to local variable last | Variable $@ may be null here. | E.cs:32:16:32:19 | last | last | -| E.cs:43:13:43:16 | access to local variable last | Variable $@ may be null here. | E.cs:32:16:32:19 | last | last | -| E.cs:61:13:61:17 | access to local variable slice | Variable $@ may be null here. | E.cs:51:22:51:26 | slice | slice | -| E.cs:112:13:112:16 | access to local variable arr2 | Variable $@ may be null here. | E.cs:107:15:107:18 | arr2 | arr2 | -| E.cs:125:33:125:35 | access to local variable obj | Variable $@ may be null here. | E.cs:119:13:119:15 | obj | obj | -| E.cs:218:9:218:9 | access to local variable x | Variable $@ may be null here. | E.cs:215:13:215:13 | x | x | -| Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ may be null here. | Forwarding.cs:7:16:7:16 | s | s | -| Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ may be null here. | Forwarding.cs:7:16:7:16 | s | s | -| GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here. | GuardedString.cs:7:16:7:16 | s | s | -| StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable $@ may be null here. | StringConcatenation.cs:14:16:14:16 | s | s | +| C.cs:64:9:64:10 | access to local variable o1 | Variable '$@' may be null here because of $@ assignment. | C.cs:62:13:62:14 | o1 | o1 | C.cs:62:13:62:46 | Object o1 = ... | this | +| C.cs:68:9:68:10 | access to local variable o2 | Variable '$@' may be null here because of $@ assignment. | C.cs:66:13:66:14 | o2 | o2 | C.cs:66:13:66:46 | Object o2 = ... | this | +| C.cs:96:15:96:15 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | C.cs:95:13:95:13 | o | o | C.cs:95:13:95:45 | Object o = ... | this | +| C.cs:104:27:104:30 | access to parameter list | Variable '$@' may be null here because of $@ assignment. | C.cs:100:42:100:45 | list | list | C.cs:103:13:103:23 | ... = ... | this | +| C.cs:178:13:178:13 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:152:13:152:13 | s | s | C.cs:179:13:179:20 | ... = ... | this | +| C.cs:204:13:204:13 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:186:13:186:13 | s | s | C.cs:205:13:205:20 | ... = ... | this | +| C.cs:224:9:224:9 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:211:13:211:13 | s | s | C.cs:223:13:223:20 | ... = ... | this | +| C.cs:243:13:243:13 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:229:16:229:16 | s | s | C.cs:241:24:241:31 | ... = ... | this | +| D.cs:23:9:23:13 | access to parameter param | Variable '$@' may be null here because of $@ null argument. | D.cs:21:32:21:36 | param | param | D.cs:17:17:17:20 | null | this | +| D.cs:32:9:32:13 | access to parameter param | Variable '$@' may be null here as suggested by $@ null check. | D.cs:26:32:26:36 | param | param | D.cs:28:13:28:25 | ... != ... | this | +| D.cs:60:13:60:14 | access to local variable o4 | Variable '$@' may be null here because of $@ assignment. | D.cs:54:13:54:14 | o4 | o4 | D.cs:54:13:54:34 | String o4 = ... | this | +| D.cs:62:13:62:14 | access to local variable o5 | Variable '$@' may be null here because of $@ assignment. | D.cs:58:13:58:14 | o5 | o5 | D.cs:58:13:58:41 | String o5 = ... | this | +| D.cs:73:13:73:14 | access to local variable o7 | Variable '$@' may be null here because of $@ assignment. | D.cs:68:13:68:14 | o7 | o7 | D.cs:68:13:68:34 | String o7 = ... | this | +| D.cs:78:13:78:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | +| D.cs:80:13:80:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | +| D.cs:82:13:82:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | +| D.cs:84:13:84:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | +| D.cs:91:13:91:14 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:94:21:94:22 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:98:21:98:22 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:102:31:102:32 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:105:19:105:20 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:134:24:134:24 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this | +| D.cs:134:24:134:24 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this | +| D.cs:135:24:135:24 | access to parameter b | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:44:125:44 | b | b | D.cs:128:20:128:28 | ... == ... | this | +| D.cs:145:20:145:20 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this | +| D.cs:145:20:145:20 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this | +| D.cs:151:9:151:11 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | D.cs:149:36:149:38 | obj | obj | D.cs:152:17:152:27 | ... != ... | this | +| D.cs:171:9:171:11 | access to local variable obj | Variable '$@' may be null here because of $@ assignment. | D.cs:163:16:163:18 | obj | obj | D.cs:163:16:163:25 | Object obj = ... | this | +| D.cs:245:13:245:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this | +| D.cs:247:13:247:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this | +| D.cs:253:13:253:14 | access to local variable o2 | Variable '$@' may be null here because of $@ assignment. | D.cs:249:13:249:14 | o2 | o2 | D.cs:249:13:249:38 | String o2 = ... | this | +| D.cs:267:13:267:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:258:16:258:23 | Object o = ... | this | +| D.cs:291:13:291:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this | +| D.cs:291:13:291:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this | +| D.cs:294:13:294:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this | +| D.cs:294:13:294:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this | +| D.cs:300:17:300:20 | access to local variable prev | Variable '$@' may be null here because of $@ assignment. | D.cs:296:16:296:19 | prev | prev | D.cs:296:16:296:26 | Object prev = ... | this | +| D.cs:313:17:313:17 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | D.cs:304:16:304:16 | s | s | D.cs:304:16:304:23 | String s = ... | this | +| D.cs:324:9:324:9 | access to local variable r | Variable '$@' may be null here because of $@ assignment. | D.cs:316:16:316:16 | r | r | D.cs:316:16:316:23 | Object r = ... | this | +| D.cs:346:9:346:11 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | D.cs:333:26:333:28 | obj | obj | D.cs:336:13:336:23 | ... == ... | this | +| D.cs:356:13:356:13 | access to local variable a | Variable '$@' may be null here because of $@ assignment. | D.cs:351:15:351:15 | a | a | D.cs:351:15:351:22 | Int32[] a = ... | this | +| D.cs:363:13:363:16 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | D.cs:360:20:360:23 | last | last | D.cs:360:20:360:30 | String last = ... | this | +| D.cs:372:13:372:13 | access to local variable b | Variable '$@' may be null here because of $@ assignment. | D.cs:366:15:366:15 | b | b | D.cs:366:15:366:47 | Int32[] b = ... | this | +| D.cs:395:20:395:20 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:388:36:388:36 | a | a | D.cs:390:20:390:28 | ... == ... | this | +| D.cs:400:20:400:20 | access to parameter b | Variable '$@' may be null here as suggested by $@ null check. | D.cs:388:45:388:45 | b | b | D.cs:397:20:397:28 | ... == ... | this | +| D.cs:410:13:410:13 | access to parameter y | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:27:407:35 | ... == ... | this | +| D.cs:410:13:410:13 | access to parameter y | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:55:407:63 | ... != ... | this | +| D.cs:410:13:410:13 | access to parameter y | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:411:13:411:21 | ... != ... | this | +| D.cs:412:13:412:13 | access to parameter x | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:14:407:22 | ... != ... | this | +| D.cs:412:13:412:13 | access to parameter x | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:42:407:50 | ... == ... | this | +| D.cs:412:13:412:13 | access to parameter x | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:409:13:409:21 | ... != ... | this | +| E.cs:12:38:12:39 | access to local variable a2 | Variable '$@' may be null here because of $@ assignment. | E.cs:9:18:9:19 | a2 | a2 | E.cs:9:18:9:26 | Int64[][] a2 = ... | this | +| E.cs:14:13:14:14 | access to local variable a3 | Variable '$@' may be null here because of $@ assignment. | E.cs:11:16:11:17 | a3 | a3 | E.cs:11:16:11:24 | Int64[] a3 = ... | this | +| E.cs:27:13:27:14 | access to local variable s1 | Variable '$@' may be null here because of $@ assignment. | E.cs:19:13:19:14 | s1 | s1 | E.cs:19:13:19:30 | String s1 = ... | this | +| E.cs:27:13:27:14 | access to local variable s1 | Variable '$@' may be null here because of $@ assignment. | E.cs:19:13:19:14 | s1 | s1 | E.cs:23:13:23:30 | ... = ... | this | +| E.cs:35:9:35:12 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:32:16:32:26 | String last = ... | this | +| E.cs:43:13:43:16 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:37:9:37:19 | ... = ... | this | +| E.cs:61:13:61:17 | access to local variable slice | Variable '$@' may be null here because of $@ assignment. | E.cs:51:22:51:26 | slice | slice | E.cs:51:22:51:33 | List slice = ... | this | +| E.cs:73:13:73:15 | access to parameter arr | Variable '$@' may be null here as suggested by $@ null check. | E.cs:66:40:66:42 | arr | arr | E.cs:70:22:70:32 | ... == ... | this | +| E.cs:93:17:93:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:83:13:83:24 | ... != ... | this | +| E.cs:93:17:93:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:85:18:85:29 | ... != ... | this | +| E.cs:98:17:98:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:83:13:83:24 | ... != ... | this | +| E.cs:98:17:98:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:85:18:85:29 | ... != ... | this | +| E.cs:112:13:112:16 | access to local variable arr2 | Variable '$@' may be null here because of $@ assignment. | E.cs:107:15:107:18 | arr2 | arr2 | E.cs:107:15:107:25 | Int32[] arr2 = ... | this | +| E.cs:125:33:125:35 | access to local variable obj | Variable '$@' may be null here because of $@ assignment. | E.cs:119:13:119:15 | obj | obj | E.cs:137:25:137:34 | ... = ... | this | +| E.cs:159:13:159:16 | access to local variable obj2 | Variable '$@' may be null here as suggested by $@ null check. | E.cs:152:16:152:19 | obj2 | obj2 | E.cs:153:13:153:24 | ... != ... | this | +| E.cs:167:21:167:21 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | E.cs:162:28:162:28 | a | a | E.cs:164:17:164:25 | ... == ... | this | +| E.cs:178:13:178:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this | +| E.cs:178:13:178:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this | +| E.cs:186:13:186:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this | +| E.cs:186:13:186:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this | +| E.cs:192:17:192:17 | access to parameter o | Variable '$@' may be null here as suggested by $@ null check. | E.cs:190:29:190:29 | o | o | E.cs:193:17:193:17 | access to parameter o | this | +| E.cs:201:11:201:11 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this | +| E.cs:203:11:203:11 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this | +| E.cs:218:9:218:9 | access to local variable x | Variable '$@' may be null here because of $@ assignment. | E.cs:215:13:215:13 | x | x | E.cs:217:13:217:20 | ... = ... | this | +| E.cs:230:9:230:9 | access to local variable x | Variable '$@' may be null here because of $@ assignment. | E.cs:225:13:225:13 | x | x | E.cs:227:13:227:20 | ... = ... | this | +| E.cs:235:16:235:16 | access to parameter i | Variable '$@' may be null here because it has a nullable type. | E.cs:233:26:233:26 | i | i | E.cs:233:26:233:26 | i | this | +| E.cs:240:21:240:21 | access to parameter i | Variable '$@' may be null here because it has a nullable type. | E.cs:238:26:238:26 | i | i | E.cs:238:26:238:26 | i | this | +| GuardedString.cs:35:31:35:31 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this | +| NullMaybeBad.cs:9:31:9:31 | access to parameter o | Variable '$@' may be null here because of $@ null argument. | NullMaybeBad.cs:7:29:7:29 | o | o | NullMaybeBad.cs:15:21:15:24 | null | this | +| StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | StringConcatenation.cs:14:16:14:16 | s | s | StringConcatenation.cs:14:16:14:23 | String s = ... | this | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybeBad.cs b/csharp/ql/test/query-tests/Nullness/NullMaybeBad.cs new file mode 100644 index 00000000000..03a6ab3d953 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/NullMaybeBad.cs @@ -0,0 +1,18 @@ +using System; + +namespace NullMaybe +{ + class Bad + { + void DoPrint(object o) + { + Console.WriteLine(o.ToString()); + } + + void M() + { + DoPrint("Hello"); + DoPrint(null); + } + } +} diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybeGood.cs b/csharp/ql/test/query-tests/Nullness/NullMaybeGood.cs new file mode 100644 index 00000000000..46c6dee1c90 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/NullMaybeGood.cs @@ -0,0 +1,19 @@ +using System; + +namespace NullMaybe +{ + class Good + { + void DoPrint(object o) + { + if (o != null) + Console.WriteLine(o.ToString()); + } + + void M() + { + DoPrint("Hello"); + DoPrint(null); + } + } +} From ab9aa7d338630d2f6b6807947fd7f91a76b25cf0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 27 Nov 2018 16:13:22 +0100 Subject: [PATCH 3/8] C#: Teach guards library about conditional assignments For example, in ``` void M(object x) { var y = x != null ? "" : null; if (y != null) x.ToString(); } ``` the guard `y != null` implies that the guard `x != null` must be true. --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 9 +- .../csharp/controlflow/ControlFlowGraph.qll | 15 +- .../semmle/code/csharp/controlflow/Guards.qll | 312 +++++++++++++++++- .../semmle/code/csharp/dataflow/Nullness.qll | 2 +- .../guards/BooleanGuardedExpr.expected | 4 + .../controlflow/guards/GuardedExpr.expected | 4 + .../controlflow/guards/Implications.expected | 18 + csharp/ql/test/query-tests/Nullness/D.cs | 4 +- .../Nullness/EqualityCheck.expected | 233 +++++++++++++ .../query-tests/Nullness/EqualityCheck.ql | 5 + .../Nullness/Implications.expected | 76 +++++ .../query-tests/Nullness/NullMaybe.expected | 3 - 12 files changed, 662 insertions(+), 23 deletions(-) create mode 100644 csharp/ql/test/query-tests/Nullness/EqualityCheck.expected create mode 100644 csharp/ql/test/query-tests/Nullness/EqualityCheck.ql diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index b8a9b7798ce..0b4ee73ace8 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -966,12 +966,17 @@ class TryStmt extends Stmt, @try_stmt { exists(ControlFlowElement mid | mid = getATriedElement() and not mid instanceof TryStmt and - result = mid.getAChild() and - mid.getEnclosingCallable() = result.getEnclosingCallable() + result = getAChild(mid, mid.getEnclosingCallable()) ) } } +pragma[noinline] +private ControlFlowElement getAChild(ControlFlowElement cfe, Callable c) { + result = cfe.getAChild() and + c = result.getEnclosingCallable() +} + /** * A `catch` clause within a `try` statement. * diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 6f353a15dc4..6f2c2a0e68d 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -2497,7 +2497,11 @@ module ControlFlow { class PreBasicBlock extends ControlFlowElement { PreBasicBlock() { startsBB(this) } - PreBasicBlock getASuccessor() { result = succ(this.getLastElement(), _) } + PreBasicBlock getASuccessorByType(SuccessorType t) { + result = succ(this.getLastElement(), any(Completion c | t.matchesCompletion(c))) + } + + PreBasicBlock getASuccessor() { result = this.getASuccessorByType(_) } PreBasicBlock getAPredecessor() { result.getASuccessor() = this @@ -3099,6 +3103,12 @@ module ControlFlow { } } + pragma[noinline] + private ControlFlowElement getAChild(ControlFlowElement cfe, Callable c) { + result = cfe.getAChild() and + c = result.getEnclosingCallable() + } + /** * Gets a descendant that belongs to the `finally` block of try statement * `try`. @@ -3108,8 +3118,7 @@ module ControlFlow { or exists(ControlFlowElement mid | mid = getAFinallyDescendant(try) and - result = mid.getAChild() and - mid.getEnclosingCallable() = result.getEnclosingCallable() and + result = getAChild(mid, mid.getEnclosingCallable()) and not exists(TryStmt nestedTry | result = nestedTry.getFinally() and nestedTry != try diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index ec1daabab99..be85ae0c542 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -9,12 +9,31 @@ private import semmle.code.csharp.commons.ComparisonTest private import semmle.code.csharp.commons.StructuralComparison::Internal private import semmle.code.csharp.controlflow.BasicBlocks private import semmle.code.csharp.controlflow.Completion +private import semmle.code.csharp.dataflow.Nullness private import semmle.code.csharp.frameworks.System /** An abstract value. */ abstract class AbstractValue extends TAbstractValue { - /** Holds if taking the `s` branch out of `cfe` implies that `e` has this value. */ - abstract predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e); + /** Holds if the `s` branch out of `cfe` is taken iff `e` has this value. */ + abstract predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e); + + /** Gets an abstract value that represents the dual of this value, if any. */ + abstract AbstractValue getDualValue(); + + /** + * Gets an expression that has this abstract value. Two expressions that have the + * same concrete value also have the same abstract value, but not necessarily the + * other way around. + * + * Moreover, `e = this.getAnExpr() implies not e = this.getDualValue().getAnExpr()`. + */ + abstract Expr getAnExpr(); + + /** + * Holds if this is a singleton abstract value. That is, two expressions that have + * this abstract value also have the same concrete value. + */ + abstract predicate isSingleton(); /** Gets a textual representation of this abstract value. */ abstract string toString(); @@ -27,7 +46,7 @@ module AbstractValues { /** Gets the underlying Boolean value. */ boolean getValue() { this = TBooleanValue(result) } - override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { + override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { s.(BooleanSuccessor).getValue() = this.getValue() and exists(BooleanCompletion c | s.matchesCompletion(c) | @@ -36,6 +55,44 @@ module AbstractValues { ) } + override BooleanValue getDualValue() { + result.getValue() = this.getValue().booleanNot() + } + + override Expr getAnExpr() { + result.getType() instanceof BoolType and + result.getValue() = this.getValue().toString() + } + + override predicate isSingleton() { any() } + + override string toString() { result = this.getValue().toString() } + } + + /** An integer value. */ + class IntergerValue extends AbstractValue, TIntegerValue { + /** Gets the underlying integer value. */ + int getValue() { this = TIntegerValue(result) } + + override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { + none() + } + + override BooleanValue getDualValue() { + none() + } + + override Expr getAnExpr() { + result.getValue().toInt() = this.getValue() and + ( + result.getType() instanceof Enum + or + result.getType() instanceof IntegralType + ) + } + + override predicate isSingleton() { any() } + override string toString() { result = this.getValue().toString() } } @@ -44,7 +101,7 @@ module AbstractValues { /** Holds if this value represents `null`. */ predicate isNull() { this = TNullValue(true) } - override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { + override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { this = TNullValue(s.(NullnessSuccessor).getValue()) and exists(NullnessCompletion c | s.matchesCompletion(c) | @@ -53,6 +110,22 @@ module AbstractValues { ) } + override NullValue getDualValue() { + if this.isNull() then not result.isNull() else result.isNull() + } + + override DereferenceableExpr getAnExpr() { + if this.isNull() then + result instanceof AlwaysNullExpr + else + exists(Expr e | + nonNullValue(e) | + nonNullValueImplied*(e, result) + ) + } + + override predicate isSingleton() { this.isNull() } + override string toString() { if this.isNull() then result = "null" else result = "non-null" } @@ -66,7 +139,7 @@ module AbstractValues { /** Holds if this value represents a match. */ predicate isMatch() { this = TMatchValue(_, true) } - override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { + override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { this = TMatchValue(_, s.(MatchingSuccessor).getValue()) and exists(MatchingCompletion c, SwitchStmt ss, CaseStmt cs | s.matchesCompletion(c) | @@ -77,6 +150,17 @@ module AbstractValues { ) } + override MatchValue getDualValue() { + result = any(MatchValue mv | + mv.getCaseStmt() = this.getCaseStmt() and + if this.isMatch() then not mv.isMatch() else mv.isMatch() + ) + } + + override Expr getAnExpr() { none() } + + override predicate isSingleton() { none() } + override string toString() { exists(string s | s = this.getCaseStmt().toString() | @@ -90,7 +174,7 @@ module AbstractValues { /** Holds if this value represents an empty collection. */ predicate isEmpty() { this = TEmptyCollectionValue(true) } - override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { + override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and exists(EmptinessCompletion c, ForeachStmt fs | s.matchesCompletion(c) | @@ -100,6 +184,14 @@ module AbstractValues { ) } + override EmptyCollectionValue getDualValue() { + if this.isEmpty() then not result.isEmpty() else result.isEmpty() + } + + override Expr getAnExpr() { none() } + + override predicate isSingleton() { none() } + override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" } @@ -164,7 +256,7 @@ class DereferenceableExpr extends Expr { ct.getExpr() = result | ct.getAnArgument() = this and ct.getAnArgument() = e and - nonNullValue(e) and + e = any(NullValue nv | not nv.isNull()).getAnExpr() and ck = ct.getComparisonKind() and this != e and isNull = false and @@ -211,7 +303,7 @@ class DereferenceableExpr extends Expr { /** * Gets an expression that tests via matching whether this expression is `null`. * - * If the returned element matches (`v.isMatch()`) or non-matches + * If the returned expression matches (`v.isMatch()`) or non-matches * (`not v.isMatch()`), then this expression is guaranteed to be `null` * if `isNull` is true, and non-`null` if `isNull` is false. * @@ -447,6 +539,10 @@ module Internal { newtype TAbstractValue = TBooleanValue(boolean b) { b = true or b = false } or + TIntegerValue(int i) { + i = any(Expr e).getValue().toInt() + } + or TNullValue(boolean b) { b = true or b = false } or TMatchValue(CaseStmt cs, boolean b) { b = true or b = false } @@ -500,7 +596,7 @@ module Internal { bao.getAnOperand() = o and // The other operand must be provably non-null in order // for `only if` to hold - nonNullValue(o) and + o = any(NullValue nv | not nv.isNull()).getAnExpr() and e != o ) } @@ -532,7 +628,7 @@ module Internal { this instanceof DereferenceableExpr and val = TNullValue(_) or - val.branchImplies(_, _, this) + val.branch(_, _, this) or asserts(_, this, val) } @@ -544,7 +640,7 @@ module Internal { predicate controls(BasicBlock bb, AbstractValue v) { exists(ControlFlowElement cfe, ConditionalSuccessor s, AbstractValue v0, Guard g | cfe.controlsBlock(bb, s) | - v0.branchImplies(cfe, s, g) and + v0.branch(cfe, s, g) and impliesSteps(g, v0, this, v) ) } @@ -586,7 +682,7 @@ module Internal { predicate preControlsDirect(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) { exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s | cb.controls(bb, s) | - v.branchImplies(cb.getLastElement(), s, this) + v.branch(cb.getLastElement(), s, this) ) } @@ -597,6 +693,14 @@ module Internal { impliesSteps(g, v0, this, v) ) } + + /** Gets the successor block that is reached when this guard has abstract value `v`. */ + PreBasicBlocks::PreBasicBlock getConditionalSuccessor(AbstractValue v) { + exists(PreBasicBlocks::ConditionBlock pred, ConditionalSuccessor s | + v.branch(pred.getLastElement(), s, this) | + result = pred.getASuccessorByType(s) + ) + } } /** @@ -699,6 +803,183 @@ module Internal { ) } + /** + * Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned + * expression `e`. + */ + private predicate conditionalAssign(Guard guard, AbstractValue vGuard, PreSsa::Definition def, Expr e) { + // For example: + // v = guard ? e : x; + exists(ConditionalExpr c | + c = def.getDefinition().getSource() | + guard = c.getCondition() and + vGuard = any(BooleanValue bv | + bv.getValue() = true and + e = c.getThen() + or + bv.getValue() = false and + e = c.getElse() + ) + ) + or + exists(PreSsa::Definition upd, PreBasicBlocks::PreBasicBlock bbGuard | + e = upd.getDefinition().getSource() and + upd = def.getAPhiInput() and + guard.preControlsDirect(upd.getBasicBlock(), vGuard) and + bbGuard.getAnElement() = guard and + bbGuard.strictlyDominates(def.getBasicBlock()) and + not guard.preControlsDirect(def.getBasicBlock(), vGuard) and + forall(PreSsa::Definition other | + other != upd and other = def.getAPhiInput() | + // For example: + // if (guard) + // upd = a; + // else + // other = b; + // def = phi(upd, other) + guard.preControlsDirect(other.getBasicBlock(), vGuard.getDualValue()) + or + // For example: + // other = a; + // if (guard) + // upd = b; + // def = phi(other, upd) + other.getBasicBlock().dominates(bbGuard) and + not PreSsa::ssaDefReachesEndOfBlock(guard.getConditionalSuccessor(vGuard), other, _) + ) + ) + } + + /** + * Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned + * an expression with abstract value `vDef`. + */ + private predicate conditionalAssignVal(Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) { + conditionalAssign(guard, vGuard, def, vDef.getAnExpr()) + } + + private predicate relevantEq(PreSsa::Definition def, AbstractValue v) { + conditionalAssignVal(_, _, def, v) + } + + /** + * Gets an expression that directly tests whether expression `e1` is equal + * to expression `e2`. + * + * If the returned expression evaluates to `v`, then expression `e1` is + * guaranteed to be equal to `e2`, otherwise it is guaranteed to not be + * equal to `e2`. + * + * For example, if the expression `x != ""` evaluates to `false` then the + * expression `x` is guaranteed to be equal to `""`. + */ + private Expr getABooleanEqualityCheck(Expr e1, BooleanValue v, Expr e2) { + exists(boolean branch | + branch = v.getValue() | + exists(ComparisonTest ct, ComparisonKind ck | + ct.getExpr() = result and + ct.getAnArgument() = e1 and + ct.getAnArgument() = e2 and + e2 != e1 and + ck = ct.getComparisonKind() | + ck.isEquality() and branch = true + or + ck.isInequality() and branch = false + ) + or + result = any(IsExpr ie | + ie.getExpr() = e1 and + e2 = ie.(IsConstantExpr).getConstant() and + branch = true + ) + ) + } + + /** + * Gets an expression that tests via matching whether expression `e1` is equal + * to expression `e2`. + * + * If the returned expression matches (`v.isMatch()`), then expression `e1` is + * guaranteed to be equal to `e2`. If the returned expression non-matches + * (`not v.isMatch()`), then this expression is guaranteed to not be equal to `e2`. + * + * For example, if the case statement `case ""` matches in + * + * ``` + * switch (o) + * { + * case "": + * return s; + * default: + * return ""; + * } + * ``` + * + * then `o` is guaranteed to be equal to `""`. + */ + private Expr getAMatchingEqualityCheck(Expr e1, MatchValue v, Expr e2) { + exists(SwitchStmt ss, ConstCase cc | + cc = v.getCaseStmt() | + e1 = ss.getCondition() and + result = e1 and + cc = ss.getACase() and + e2 = cc.getExpr() and + v.isMatch() + ) + } + + /** + * Gets an expression that tests whether expression `e1` is equal to + * expression `e2`. + * + * If the returned expression has abstract value `v`, then expression `e1` is + * guaranteed to be equal to `e2`, and if the returned expression has abstract + * value `v.getDualValue()`, then this expression is guaranteed to be + * non-equal to `e`. + * + * For example, if the expression `x != ""` evaluates to `false` then the + * expression `x` is guaranteed to be equal to `""`. + */ + Expr getAnEqualityCheck(Expr e1, AbstractValue v, Expr e2) { + result = getABooleanEqualityCheck(e1, v, e2) + or + result = getAMatchingEqualityCheck(e1, v, e2) + } + + private Expr getAnEqualityCheckVal(Expr e, AbstractValue v, AbstractValue vExpr) { + result = getAnEqualityCheck(e, v, vExpr.getAnExpr()) + } + + /** + * Holds if the evaluation of `guard` to `vGuard` implies that `def` does not + * have the value `vDef`. + */ + private predicate guardImpliesNotEqual(Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) { + relevantEq(def, vDef) and + exists(DereferenceableExpr de | + de = def.getARead() | + // For example: + // if (de == null); vGuard = TBooleanValue(false); vDef = TNullValue(true) + // but not + // if (de == "abc"); vGuard = TBooleanValue(false); vDef = TNullValue(false) + guard = getAnEqualityCheckVal(de, vGuard.getDualValue(), vDef) and + vDef.isSingleton() + or + // For example: + // if (de != null); vGuard = TBooleanValue(true); vDef = TNullValue(true) + // or + // if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false) + exists(NullValue nv | + guard = de.getANullCheck(vGuard, any(boolean b | nv = TNullValue(b))) | + vDef = nv.getDualValue() + ) + or + // For example: + // if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false) + guard = getAnEqualityCheckVal(de, vGuard, vDef.getDualValue()) + ) + } + /** * A helper class for calculating structurally equal access/call expressions. */ @@ -879,6 +1160,13 @@ module Internal { v1 = g1.getAValue() and v2 = v1 ) + or + exists(PreSsa::Definition def, AbstractValue v | + // If `def = g2 ? v : ...` or `def = g2 ? ... : v` then a guard `g1` + // proving `def != v` ensures that `g2` evaluates to `b2`. + conditionalAssignVal(g2, v2.getDualValue(), def, v) and + guardImpliesNotEqual(g1, v1, def, v) + ) } cached diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll index cafcee66f94..7cbf21232da 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll @@ -142,7 +142,7 @@ private predicate potentialNullDereferenceAt(BasicBlock bb, int i, Ssa::Definiti */ private ControlFlowElement getANullCheck(Ssa::Definition def, SuccessorTypes::ConditionalSuccessor s, NullValue nv) { exists(Expr e, G::AbstractValue v | - v.branchImplies(result, s, e) | + v.branch(result, s, e) | exprImpliesSsaDef(e, v, def, nv) ) } diff --git a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected index 16961a823d2..36d7e34c341 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected @@ -3,12 +3,16 @@ | Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true | | Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false | | Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index 054ec6f7403..3e3d977d71b 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -10,18 +10,22 @@ | Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false | | Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | non-null | | Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | | Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | non-null | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | | Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | non-null | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | | Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | null | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | | Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index d6bbe4af6f7..7c68d807a82 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -2,7 +2,9 @@ | Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null | | Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | +| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:9:20:9:20 | access to parameter b | true | | Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null | +| Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:9:20:9:20 | access to parameter b | false | | Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null | | Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | @@ -22,7 +24,9 @@ | Assert.cs:30:16:30:32 | String s = ... | null | Assert.cs:30:16:30:16 | access to local variable s | null | | Assert.cs:31:23:31:23 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | | Assert.cs:31:23:31:23 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | +| Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:30:20:30:20 | access to parameter b | false | | Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:31:23:31:23 | access to local variable s | non-null | +| Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:30:20:30:20 | access to parameter b | true | | Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:31:23:31:23 | access to local variable s | null | | Assert.cs:32:27:32:27 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | | Assert.cs:32:27:32:27 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | @@ -30,7 +34,9 @@ | Assert.cs:37:16:37:32 | String s = ... | null | Assert.cs:37:16:37:16 | access to local variable s | null | | Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | | Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | +| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:37:20:37:20 | access to parameter b | true | | Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null | +| Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:37:20:37:20 | access to parameter b | false | | Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null | | Assert.cs:39:27:39:27 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | | Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | @@ -38,7 +44,9 @@ | Assert.cs:44:16:44:32 | String s = ... | null | Assert.cs:44:16:44:16 | access to local variable s | null | | Assert.cs:45:24:45:24 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | | Assert.cs:45:24:45:24 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | +| Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:44:20:44:20 | access to parameter b | true | | Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:45:24:45:24 | access to local variable s | null | +| Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:44:20:44:20 | access to parameter b | false | | Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:45:24:45:24 | access to local variable s | non-null | | Assert.cs:46:27:46:27 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | | Assert.cs:46:27:46:27 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | @@ -46,7 +54,9 @@ | Assert.cs:51:16:51:32 | String s = ... | null | Assert.cs:51:16:51:16 | access to local variable s | null | | Assert.cs:52:24:52:24 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | | Assert.cs:52:24:52:24 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | +| Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:51:20:51:20 | access to parameter b | false | | Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:52:24:52:24 | access to local variable s | non-null | +| Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:51:20:51:20 | access to parameter b | true | | Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:52:24:52:24 | access to local variable s | null | | Assert.cs:53:27:53:27 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | | Assert.cs:53:27:53:27 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | @@ -54,7 +64,9 @@ | Assert.cs:58:16:58:32 | String s = ... | null | Assert.cs:58:16:58:16 | access to local variable s | null | | Assert.cs:59:23:59:23 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | | Assert.cs:59:23:59:23 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null | +| Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:58:20:58:20 | access to parameter b | true | | Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:59:23:59:23 | access to local variable s | null | +| Assert.cs:59:23:59:31 | ... != ... | true | Assert.cs:58:20:58:20 | access to parameter b | false | | Assert.cs:59:23:59:31 | ... != ... | true | Assert.cs:59:23:59:23 | access to local variable s | non-null | | Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:23:59:31 | ... != ... | true | | Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:36:59:36 | access to parameter b | true | @@ -64,7 +76,9 @@ | Assert.cs:65:16:65:32 | String s = ... | null | Assert.cs:65:16:65:16 | access to local variable s | null | | Assert.cs:66:24:66:24 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | | Assert.cs:66:24:66:24 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null | +| Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:65:20:65:20 | access to parameter b | false | | Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:66:24:66:24 | access to local variable s | non-null | +| Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:65:20:65:20 | access to parameter b | true | | Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:66:24:66:24 | access to local variable s | null | | Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:24:66:32 | ... == ... | false | | Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:37:66:37 | access to parameter b | false | @@ -74,7 +88,9 @@ | Assert.cs:72:16:72:32 | String s = ... | null | Assert.cs:72:16:72:16 | access to local variable s | null | | Assert.cs:73:23:73:23 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | | Assert.cs:73:23:73:23 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null | +| Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:72:20:72:20 | access to parameter b | false | | Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:73:23:73:23 | access to local variable s | non-null | +| Assert.cs:73:23:73:31 | ... == ... | true | Assert.cs:72:20:72:20 | access to parameter b | true | | Assert.cs:73:23:73:31 | ... == ... | true | Assert.cs:73:23:73:23 | access to local variable s | null | | Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:23:73:31 | ... == ... | true | | Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:36:73:36 | access to parameter b | true | @@ -84,7 +100,9 @@ | Assert.cs:79:16:79:32 | String s = ... | null | Assert.cs:79:16:79:16 | access to local variable s | null | | Assert.cs:80:24:80:24 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | | Assert.cs:80:24:80:24 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null | +| Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:79:20:79:20 | access to parameter b | true | | Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:80:24:80:24 | access to local variable s | null | +| Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:79:20:79:20 | access to parameter b | false | | Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:80:24:80:24 | access to local variable s | non-null | | Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:24:80:32 | ... != ... | false | | Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:37:80:37 | access to parameter b | false | diff --git a/csharp/ql/test/query-tests/Nullness/D.cs b/csharp/ql/test/query-tests/Nullness/D.cs index 83feebd3766..ae0563ad813 100644 --- a/csharp/ql/test/query-tests/Nullness/D.cs +++ b/csharp/ql/test/query-tests/Nullness/D.cs @@ -57,7 +57,7 @@ public class D var o5 = (o4 != null) ? "" : null; if (o5 != null) - o4.ToString(); // GOOD (false positive) + o4.ToString(); // GOOD if (o4 != null) o5.ToString(); // GOOD (false positive) @@ -343,7 +343,7 @@ public class D msg += "foobar"; throw new Exception(msg); } - obj.ToString(); // GOOD (false positive) + obj.ToString(); // GOOD } public void LoopCorr(int iters) diff --git a/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected new file mode 100644 index 00000000000..948bf1751a3 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected @@ -0,0 +1,233 @@ +| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:27:10:30 | null | +| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:27:10:30 | null | Assert.cs:10:22:10:22 | access to local variable s | +| Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:22:23:22:23 | access to local variable s | Assert.cs:22:28:22:31 | null | +| Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:22:28:22:31 | null | Assert.cs:22:23:22:23 | access to local variable s | +| Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:26:23:26:23 | access to local variable s | Assert.cs:26:28:26:31 | null | +| Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:26:28:26:31 | null | Assert.cs:26:23:26:23 | access to local variable s | +| Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:30:24:30:24 | access to local variable s | Assert.cs:30:29:30:32 | null | +| Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:30:29:30:32 | null | Assert.cs:30:24:30:24 | access to local variable s | +| Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:34:24:34:24 | access to local variable s | Assert.cs:34:29:34:32 | null | +| Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:34:29:34:32 | null | Assert.cs:34:24:34:24 | access to local variable s | +| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:28:38:31 | null | +| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:28:38:31 | null | Assert.cs:38:23:38:23 | access to local variable s | +| Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:42:24:42:24 | access to local variable s | Assert.cs:42:29:42:32 | null | +| Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:42:29:42:32 | null | Assert.cs:42:24:42:24 | access to local variable s | +| Assert.cs:46:23:46:31 | ... == ... | true | Assert.cs:46:23:46:23 | access to local variable s | Assert.cs:46:28:46:31 | null | +| Assert.cs:46:23:46:31 | ... == ... | true | Assert.cs:46:28:46:31 | null | Assert.cs:46:23:46:23 | access to local variable s | +| Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:24:50:24 | access to local variable s | Assert.cs:50:29:50:32 | null | +| Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:29:50:32 | null | Assert.cs:50:24:50:24 | access to local variable s | +| B.cs:12:13:12:32 | call to operator == | true | B.cs:12:13:12:24 | access to local variable eqCallAlways | B.cs:12:29:12:32 | null | +| B.cs:12:13:12:32 | call to operator == | true | B.cs:12:29:12:32 | null | B.cs:12:13:12:24 | access to local variable eqCallAlways | +| B.cs:15:13:15:22 | call to operator != | false | B.cs:15:13:15:14 | access to local variable b2 | B.cs:15:19:15:22 | null | +| B.cs:15:13:15:22 | call to operator != | false | B.cs:15:19:15:22 | null | B.cs:15:13:15:14 | access to local variable b2 | +| B.cs:18:13:18:22 | call to operator == | true | B.cs:18:13:18:14 | access to local variable b3 | B.cs:18:19:18:22 | null | +| B.cs:18:13:18:22 | call to operator == | true | B.cs:18:19:18:22 | null | B.cs:18:13:18:14 | access to local variable b3 | +| B.cs:22:13:22:33 | call to operator != | false | B.cs:22:13:22:25 | access to local variable neqCallAlways | B.cs:22:30:22:33 | null | +| B.cs:22:13:22:33 | call to operator != | false | B.cs:22:30:22:33 | null | B.cs:22:13:22:25 | access to local variable neqCallAlways | +| B.cs:29:16:29:36 | call to method Equals | true | B.cs:29:30:29:31 | access to parameter b1 | B.cs:29:34:29:35 | access to parameter b2 | +| B.cs:29:16:29:36 | call to method Equals | true | B.cs:29:34:29:35 | access to parameter b2 | B.cs:29:30:29:31 | access to parameter b1 | +| B.cs:34:18:34:25 | call to operator == | true | B.cs:34:18:34:19 | access to parameter b1 | B.cs:34:24:34:25 | access to parameter b2 | +| B.cs:34:18:34:25 | call to operator == | true | B.cs:34:24:34:25 | access to parameter b2 | B.cs:34:18:34:19 | access to parameter b1 | +| B.cs:53:17:53:33 | ... != ... | false | B.cs:53:17:53:25 | (...) ... | B.cs:53:30:53:33 | null | +| B.cs:53:17:53:33 | ... != ... | false | B.cs:53:30:53:33 | null | B.cs:53:17:53:25 | (...) ... | +| B.cs:55:26:55:36 | call to method Equals | true | B.cs:55:26:55:26 | access to local variable o | B.cs:55:35:55:35 | access to local variable o | +| B.cs:55:26:55:36 | call to method Equals | true | B.cs:55:35:55:35 | access to local variable o | B.cs:55:26:55:26 | access to local variable o | +| C.cs:11:19:11:27 | ... == ... | true | C.cs:11:19:11:19 | access to local variable o | C.cs:11:24:11:27 | null | +| C.cs:11:19:11:27 | ... == ... | true | C.cs:11:24:11:27 | null | C.cs:11:19:11:19 | access to local variable o | +| C.cs:16:15:16:23 | ... != ... | false | C.cs:16:15:16:15 | access to local variable o | C.cs:16:20:16:23 | null | +| C.cs:16:15:16:23 | ... != ... | false | C.cs:16:20:16:23 | null | C.cs:16:15:16:15 | access to local variable o | +| C.cs:24:13:24:21 | ... != ... | false | C.cs:24:13:24:13 | access to parameter o | C.cs:24:18:24:21 | null | +| C.cs:24:13:24:21 | ... != ... | false | C.cs:24:18:24:21 | null | C.cs:24:13:24:13 | access to parameter o | +| C.cs:28:37:28:45 | ... == ... | true | C.cs:28:37:28:37 | access to parameter o | C.cs:28:42:28:45 | null | +| C.cs:28:37:28:45 | ... == ... | true | C.cs:28:42:28:45 | null | C.cs:28:37:28:37 | access to parameter o | +| C.cs:30:40:30:48 | ... != ... | false | C.cs:30:40:30:40 | access to parameter o | C.cs:30:45:30:48 | null | +| C.cs:30:40:30:48 | ... != ... | false | C.cs:30:45:30:48 | null | C.cs:30:40:30:40 | access to parameter o | +| C.cs:34:13:34:21 | ... == ... | true | C.cs:34:13:34:13 | access to parameter o | C.cs:34:18:34:21 | null | +| C.cs:34:13:34:21 | ... == ... | true | C.cs:34:18:34:21 | null | C.cs:34:13:34:13 | access to parameter o | +| C.cs:41:22:41:30 | ... == ... | true | C.cs:41:22:41:22 | access to local variable s | C.cs:41:27:41:30 | null | +| C.cs:41:22:41:30 | ... == ... | true | C.cs:41:27:41:30 | null | C.cs:41:22:41:22 | access to local variable s | +| C.cs:45:22:45:30 | ... != ... | false | C.cs:45:22:45:22 | access to local variable s | C.cs:45:27:45:30 | null | +| C.cs:45:22:45:30 | ... != ... | false | C.cs:45:27:45:30 | null | C.cs:45:22:45:22 | access to local variable s | +| C.cs:114:22:114:36 | ... == ... | true | C.cs:114:22:114:28 | access to local variable colours | C.cs:114:33:114:36 | null | +| C.cs:114:22:114:36 | ... == ... | true | C.cs:114:33:114:36 | null | C.cs:114:22:114:28 | access to local variable colours | +| C.cs:114:41:114:59 | ... == ... | true | C.cs:114:41:114:54 | access to property Length | C.cs:114:59:114:59 | 0 | +| C.cs:114:41:114:59 | ... == ... | true | C.cs:114:59:114:59 | 0 | C.cs:114:41:114:54 | access to property Length | +| C.cs:121:13:121:28 | ... == ... | true | C.cs:121:13:121:20 | access to local variable children | C.cs:121:25:121:28 | null | +| C.cs:121:13:121:28 | ... == ... | true | C.cs:121:25:121:28 | null | C.cs:121:13:121:20 | access to local variable children | +| C.cs:130:13:130:38 | ... == ... | true | C.cs:130:14:130:29 | ... = ... | C.cs:130:35:130:38 | null | +| C.cs:130:13:130:38 | ... == ... | true | C.cs:130:35:130:38 | null | C.cs:130:14:130:29 | ... = ... | +| C.cs:146:13:146:39 | ... != ... | false | C.cs:146:14:146:30 | ... = ... | C.cs:146:36:146:39 | null | +| C.cs:146:13:146:39 | ... != ... | false | C.cs:146:36:146:39 | null | C.cs:146:14:146:30 | ... = ... | +| C.cs:158:16:158:24 | ... != ... | false | C.cs:158:16:158:16 | access to local variable s | C.cs:158:21:158:24 | null | +| C.cs:158:16:158:24 | ... != ... | false | C.cs:158:21:158:24 | null | C.cs:158:16:158:16 | access to local variable s | +| C.cs:166:16:166:24 | ... != ... | false | C.cs:166:16:166:16 | access to local variable s | C.cs:166:21:166:24 | null | +| C.cs:166:16:166:24 | ... != ... | false | C.cs:166:21:166:24 | null | C.cs:166:16:166:16 | access to local variable s | +| C.cs:173:16:173:24 | ... != ... | false | C.cs:173:16:173:16 | access to local variable s | C.cs:173:21:173:24 | null | +| C.cs:173:16:173:24 | ... != ... | false | C.cs:173:21:173:24 | null | C.cs:173:16:173:16 | access to local variable s | +| C.cs:187:16:187:24 | ... != ... | false | C.cs:187:16:187:16 | access to local variable s | C.cs:187:21:187:24 | null | +| C.cs:187:16:187:24 | ... != ... | false | C.cs:187:21:187:24 | null | C.cs:187:16:187:16 | access to local variable s | +| C.cs:212:13:212:21 | ... != ... | false | C.cs:212:13:212:13 | access to local variable s | C.cs:212:18:212:21 | null | +| C.cs:212:13:212:21 | ... != ... | false | C.cs:212:18:212:21 | null | C.cs:212:13:212:13 | access to local variable s | +| C.cs:218:13:218:21 | ... == ... | true | C.cs:218:13:218:13 | access to local variable s | C.cs:218:18:218:21 | null | +| C.cs:218:13:218:21 | ... == ... | true | C.cs:218:18:218:21 | null | C.cs:218:13:218:13 | access to local variable s | +| C.cs:222:13:222:21 | ... != ... | false | C.cs:222:13:222:13 | access to local variable s | C.cs:222:18:222:21 | null | +| C.cs:222:13:222:21 | ... != ... | false | C.cs:222:18:222:21 | null | C.cs:222:13:222:13 | access to local variable s | +| C.cs:222:26:222:42 | ... == ... | true | C.cs:222:26:222:37 | ... % ... | C.cs:222:42:222:42 | 0 | +| C.cs:222:26:222:42 | ... == ... | true | C.cs:222:42:222:42 | 0 | C.cs:222:26:222:37 | ... % ... | +| C.cs:230:22:230:30 | ... != ... | false | C.cs:230:22:230:22 | access to local variable s | C.cs:230:27:230:30 | null | +| C.cs:230:22:230:30 | ... != ... | false | C.cs:230:27:230:30 | null | C.cs:230:22:230:22 | access to local variable s | +| C.cs:236:24:236:32 | ... == ... | true | C.cs:236:24:236:24 | access to local variable s | C.cs:236:29:236:32 | null | +| C.cs:236:24:236:32 | ... == ... | true | C.cs:236:29:236:32 | null | C.cs:236:24:236:24 | access to local variable s | +| D.cs:28:13:28:25 | ... != ... | false | D.cs:28:13:28:17 | access to parameter param | D.cs:28:22:28:25 | null | +| D.cs:28:13:28:25 | ... != ... | false | D.cs:28:22:28:25 | null | D.cs:28:13:28:17 | access to parameter param | +| D.cs:38:13:38:21 | ... == ... | true | D.cs:38:13:38:13 | access to parameter x | D.cs:38:18:38:21 | null | +| D.cs:38:13:38:21 | ... == ... | true | D.cs:38:18:38:21 | null | D.cs:38:13:38:13 | access to parameter x | +| D.cs:39:16:39:24 | ... == ... | true | D.cs:39:16:39:16 | access to parameter x | D.cs:39:21:39:24 | null | +| D.cs:39:16:39:24 | ... == ... | true | D.cs:39:21:39:24 | null | D.cs:39:16:39:16 | access to parameter x | +| D.cs:45:13:45:22 | ... != ... | false | D.cs:45:13:45:14 | access to local variable o1 | D.cs:45:19:45:22 | null | +| D.cs:45:13:45:22 | ... != ... | false | D.cs:45:19:45:22 | null | D.cs:45:13:45:14 | access to local variable o1 | +| D.cs:51:13:51:44 | ... != ... | false | D.cs:51:14:51:35 | ... = ... | D.cs:51:41:51:44 | null | +| D.cs:51:13:51:44 | ... != ... | false | D.cs:51:41:51:44 | null | D.cs:51:14:51:35 | ... = ... | +| D.cs:55:13:55:42 | ... != ... | false | D.cs:55:14:55:32 | ... && ... | D.cs:55:38:55:42 | false | +| D.cs:55:13:55:42 | ... != ... | false | D.cs:55:38:55:42 | false | D.cs:55:14:55:32 | ... && ... | +| D.cs:55:23:55:32 | ... != ... | false | D.cs:55:23:55:24 | access to local variable o4 | D.cs:55:29:55:32 | null | +| D.cs:55:23:55:32 | ... != ... | false | D.cs:55:29:55:32 | null | D.cs:55:23:55:24 | access to local variable o4 | +| D.cs:58:19:58:28 | ... != ... | false | D.cs:58:19:58:20 | access to local variable o4 | D.cs:58:25:58:28 | null | +| D.cs:58:19:58:28 | ... != ... | false | D.cs:58:25:58:28 | null | D.cs:58:19:58:20 | access to local variable o4 | +| D.cs:59:13:59:22 | ... != ... | false | D.cs:59:13:59:14 | access to local variable o5 | D.cs:59:19:59:22 | null | +| D.cs:59:13:59:22 | ... != ... | false | D.cs:59:19:59:22 | null | D.cs:59:13:59:14 | access to local variable o5 | +| D.cs:61:13:61:22 | ... != ... | false | D.cs:61:13:61:14 | access to local variable o4 | D.cs:61:19:61:22 | null | +| D.cs:61:13:61:22 | ... != ... | false | D.cs:61:19:61:22 | null | D.cs:61:13:61:14 | access to local variable o4 | +| D.cs:69:18:69:27 | ... != ... | false | D.cs:69:18:69:19 | access to local variable o7 | D.cs:69:24:69:27 | null | +| D.cs:69:18:69:27 | ... != ... | false | D.cs:69:24:69:27 | null | D.cs:69:18:69:19 | access to local variable o7 | +| D.cs:76:21:76:30 | ... == ... | true | D.cs:76:21:76:22 | access to local variable o8 | D.cs:76:27:76:30 | null | +| D.cs:76:21:76:30 | ... == ... | true | D.cs:76:27:76:30 | null | D.cs:76:21:76:22 | access to local variable o8 | +| D.cs:77:13:77:22 | ... == ... | true | D.cs:77:13:77:17 | access to local variable track | D.cs:77:22:77:22 | 2 | +| D.cs:77:13:77:22 | ... == ... | true | D.cs:77:22:77:22 | 2 | D.cs:77:13:77:17 | access to local variable track | +| D.cs:79:13:79:23 | ... != ... | false | D.cs:79:13:79:17 | access to local variable track | D.cs:79:22:79:23 | 42 | +| D.cs:79:13:79:23 | ... != ... | false | D.cs:79:22:79:23 | 42 | D.cs:79:13:79:17 | access to local variable track | +| D.cs:110:26:110:35 | ... != ... | false | D.cs:110:26:110:27 | access to local variable xs | D.cs:110:32:110:35 | null | +| D.cs:110:26:110:35 | ... != ... | false | D.cs:110:32:110:35 | null | D.cs:110:26:110:27 | access to local variable xs | +| D.cs:118:13:118:21 | ... == ... | true | D.cs:118:13:118:13 | access to local variable x | D.cs:118:18:118:21 | null | +| D.cs:118:13:118:21 | ... == ... | true | D.cs:118:18:118:21 | null | D.cs:118:13:118:13 | access to local variable x | +| D.cs:119:13:119:21 | ... == ... | true | D.cs:119:13:119:13 | access to local variable x | D.cs:119:18:119:21 | null | +| D.cs:119:13:119:21 | ... == ... | true | D.cs:119:18:119:21 | null | D.cs:119:13:119:13 | access to local variable x | +| D.cs:127:20:127:28 | ... == ... | true | D.cs:127:20:127:20 | access to parameter a | D.cs:127:25:127:28 | null | +| D.cs:127:20:127:28 | ... == ... | true | D.cs:127:25:127:28 | null | D.cs:127:20:127:20 | access to parameter a | +| D.cs:128:20:128:28 | ... == ... | true | D.cs:128:20:128:20 | access to parameter b | D.cs:128:25:128:28 | null | +| D.cs:128:20:128:28 | ... == ... | true | D.cs:128:25:128:28 | null | D.cs:128:20:128:20 | access to parameter b | +| D.cs:130:13:130:24 | ... == ... | true | D.cs:130:13:130:16 | access to local variable alen | D.cs:130:21:130:24 | access to local variable blen | +| D.cs:130:13:130:24 | ... == ... | true | D.cs:130:21:130:24 | access to local variable blen | D.cs:130:13:130:16 | access to local variable alen | +| D.cs:139:13:139:21 | ... != ... | false | D.cs:139:13:139:13 | access to parameter a | D.cs:139:18:139:21 | null | +| D.cs:139:13:139:21 | ... != ... | false | D.cs:139:18:139:21 | null | D.cs:139:13:139:13 | access to parameter a | +| D.cs:152:17:152:27 | ... != ... | false | D.cs:152:17:152:19 | access to parameter obj | D.cs:152:24:152:27 | null | +| D.cs:152:17:152:27 | ... != ... | false | D.cs:152:24:152:27 | null | D.cs:152:17:152:19 | access to parameter obj | +| D.cs:196:13:196:21 | ... == ... | true | D.cs:196:13:196:13 | access to local variable o | D.cs:196:18:196:21 | null | +| D.cs:196:13:196:21 | ... == ... | true | D.cs:196:18:196:21 | null | D.cs:196:13:196:13 | access to local variable o | +| D.cs:206:17:206:25 | ... == ... | true | D.cs:206:17:206:17 | access to local variable e | D.cs:206:22:206:25 | null | +| D.cs:206:17:206:25 | ... == ... | true | D.cs:206:22:206:25 | null | D.cs:206:17:206:17 | access to local variable e | +| D.cs:212:18:212:26 | ... == ... | true | D.cs:212:18:212:18 | access to local variable n | D.cs:212:23:212:26 | null | +| D.cs:212:18:212:26 | ... == ... | true | D.cs:212:23:212:26 | null | D.cs:212:18:212:18 | access to local variable n | +| D.cs:216:13:216:22 | ... == ... | true | D.cs:216:13:216:14 | access to local variable o3 | D.cs:216:19:216:22 | null | +| D.cs:216:13:216:22 | ... == ... | true | D.cs:216:19:216:22 | null | D.cs:216:13:216:14 | access to local variable o3 | +| D.cs:221:13:221:22 | ... == ... | true | D.cs:221:13:221:14 | access to local variable o4 | D.cs:221:19:221:22 | null | +| D.cs:221:13:221:22 | ... == ... | true | D.cs:221:19:221:22 | null | D.cs:221:13:221:14 | access to local variable o4 | +| D.cs:242:13:242:25 | ... == ... | true | D.cs:242:13:242:17 | access to local variable other | D.cs:242:22:242:25 | null | +| D.cs:242:13:242:25 | ... == ... | true | D.cs:242:22:242:25 | null | D.cs:242:13:242:17 | access to local variable other | +| D.cs:244:13:244:25 | ... != ... | false | D.cs:244:13:244:17 | access to local variable other | D.cs:244:22:244:25 | null | +| D.cs:244:13:244:25 | ... != ... | false | D.cs:244:22:244:25 | null | D.cs:244:13:244:17 | access to local variable other | +| D.cs:274:17:274:26 | ... == ... | true | D.cs:274:17:274:20 | access to array element | D.cs:274:25:274:26 | 42 | +| D.cs:274:17:274:26 | ... == ... | true | D.cs:274:25:274:26 | 42 | D.cs:274:17:274:20 | access to array element | +| D.cs:299:17:299:22 | ... != ... | false | D.cs:299:17:299:17 | access to local variable i | D.cs:299:22:299:22 | 0 | +| D.cs:299:17:299:22 | ... != ... | false | D.cs:299:22:299:22 | 0 | D.cs:299:17:299:17 | access to local variable i | +| D.cs:318:16:318:36 | ... == ... | true | D.cs:318:16:318:19 | access to local variable stat | D.cs:318:24:318:36 | access to constant INIT | +| D.cs:318:16:318:36 | ... == ... | true | D.cs:318:24:318:36 | access to constant INIT | D.cs:318:16:318:19 | access to local variable stat | +| D.cs:318:41:318:62 | ... != ... | false | D.cs:318:41:318:44 | access to local variable stat | D.cs:318:49:318:62 | access to constant READY | +| D.cs:318:41:318:62 | ... != ... | false | D.cs:318:49:318:62 | access to constant READY | D.cs:318:41:318:44 | access to local variable stat | +| D.cs:321:17:321:37 | ... == ... | true | D.cs:321:17:321:20 | access to local variable stat | D.cs:321:25:321:37 | access to constant INIT | +| D.cs:321:17:321:37 | ... == ... | true | D.cs:321:25:321:37 | access to constant INIT | D.cs:321:17:321:20 | access to local variable stat | +| D.cs:336:13:336:23 | ... == ... | true | D.cs:336:13:336:15 | access to parameter obj | D.cs:336:20:336:23 | null | +| D.cs:336:13:336:23 | ... == ... | true | D.cs:336:20:336:23 | null | D.cs:336:13:336:15 | access to parameter obj | +| D.cs:341:13:341:23 | ... != ... | false | D.cs:341:13:341:15 | access to local variable msg | D.cs:341:20:341:23 | null | +| D.cs:341:13:341:23 | ... != ... | false | D.cs:341:20:341:23 | null | D.cs:341:13:341:15 | access to local variable msg | +| D.cs:367:27:367:35 | ... == ... | true | D.cs:367:27:367:27 | access to local variable b | D.cs:367:32:367:35 | null | +| D.cs:367:27:367:35 | ... == ... | true | D.cs:367:32:367:35 | null | D.cs:367:27:367:27 | access to local variable b | +| D.cs:382:13:382:23 | ... != ... | false | D.cs:382:13:382:15 | access to local variable ioe | D.cs:382:20:382:23 | null | +| D.cs:382:13:382:23 | ... != ... | false | D.cs:382:20:382:23 | null | D.cs:382:13:382:15 | access to local variable ioe | +| D.cs:390:20:390:28 | ... == ... | true | D.cs:390:20:390:20 | access to parameter a | D.cs:390:25:390:28 | null | +| D.cs:390:20:390:28 | ... == ... | true | D.cs:390:25:390:28 | null | D.cs:390:20:390:20 | access to parameter a | +| D.cs:397:20:397:28 | ... == ... | true | D.cs:397:20:397:20 | access to parameter b | D.cs:397:25:397:28 | null | +| D.cs:397:20:397:28 | ... == ... | true | D.cs:397:25:397:28 | null | D.cs:397:20:397:20 | access to parameter b | +| D.cs:407:14:407:22 | ... != ... | false | D.cs:407:14:407:14 | access to parameter x | D.cs:407:19:407:22 | null | +| D.cs:407:14:407:22 | ... != ... | false | D.cs:407:19:407:22 | null | D.cs:407:14:407:14 | access to parameter x | +| D.cs:407:27:407:35 | ... == ... | true | D.cs:407:27:407:27 | access to parameter y | D.cs:407:32:407:35 | null | +| D.cs:407:27:407:35 | ... == ... | true | D.cs:407:32:407:35 | null | D.cs:407:27:407:27 | access to parameter y | +| D.cs:407:42:407:50 | ... == ... | true | D.cs:407:42:407:42 | access to parameter x | D.cs:407:47:407:50 | null | +| D.cs:407:42:407:50 | ... == ... | true | D.cs:407:47:407:50 | null | D.cs:407:42:407:42 | access to parameter x | +| D.cs:407:55:407:63 | ... != ... | false | D.cs:407:55:407:55 | access to parameter y | D.cs:407:60:407:63 | null | +| D.cs:407:55:407:63 | ... != ... | false | D.cs:407:60:407:63 | null | D.cs:407:55:407:55 | access to parameter y | +| D.cs:409:13:409:21 | ... != ... | false | D.cs:409:13:409:13 | access to parameter x | D.cs:409:18:409:21 | null | +| D.cs:409:13:409:21 | ... != ... | false | D.cs:409:18:409:21 | null | D.cs:409:13:409:13 | access to parameter x | +| D.cs:411:13:411:21 | ... != ... | false | D.cs:411:13:411:13 | access to parameter y | D.cs:411:18:411:21 | null | +| D.cs:411:13:411:21 | ... != ... | false | D.cs:411:18:411:21 | null | D.cs:411:13:411:13 | access to parameter y | +| E.cs:10:34:10:54 | ... != ... | false | E.cs:10:35:10:45 | ... = ... | E.cs:10:51:10:54 | null | +| E.cs:10:34:10:54 | ... != ... | false | E.cs:10:51:10:54 | null | E.cs:10:35:10:45 | ... = ... | +| E.cs:12:32:12:52 | ... != ... | false | E.cs:12:33:12:43 | ... = ... | E.cs:12:49:12:52 | null | +| E.cs:12:32:12:52 | ... != ... | false | E.cs:12:49:12:52 | null | E.cs:12:33:12:43 | ... = ... | +| E.cs:20:19:20:28 | ... == ... | true | E.cs:20:19:20:20 | access to local variable s1 | E.cs:20:25:20:28 | null | +| E.cs:20:19:20:28 | ... == ... | true | E.cs:20:25:20:28 | null | E.cs:20:19:20:20 | access to local variable s1 | +| E.cs:21:13:21:22 | ... == ... | true | E.cs:21:13:21:14 | access to local variable s2 | E.cs:21:19:21:22 | null | +| E.cs:21:13:21:22 | ... == ... | true | E.cs:21:19:21:22 | null | E.cs:21:13:21:14 | access to local variable s2 | +| E.cs:24:19:24:28 | ... == ... | true | E.cs:24:19:24:20 | access to local variable s1 | E.cs:24:25:24:28 | null | +| E.cs:24:19:24:28 | ... == ... | true | E.cs:24:25:24:28 | null | E.cs:24:19:24:20 | access to local variable s1 | +| E.cs:26:13:26:22 | ... != ... | false | E.cs:26:13:26:14 | access to local variable s2 | E.cs:26:19:26:22 | null | +| E.cs:26:13:26:22 | ... != ... | false | E.cs:26:19:26:22 | null | E.cs:26:13:26:14 | access to local variable s2 | +| E.cs:56:17:56:33 | ... == ... | true | E.cs:56:17:56:28 | ... % ... | E.cs:56:33:56:33 | 0 | +| E.cs:56:17:56:33 | ... == ... | true | E.cs:56:33:56:33 | 0 | E.cs:56:17:56:28 | ... % ... | +| E.cs:70:22:70:32 | ... == ... | true | E.cs:70:22:70:24 | access to parameter arr | E.cs:70:29:70:32 | null | +| E.cs:70:22:70:32 | ... == ... | true | E.cs:70:29:70:32 | null | E.cs:70:22:70:24 | access to parameter arr | +| E.cs:83:13:83:24 | ... != ... | false | E.cs:83:13:83:16 | access to parameter vals | E.cs:83:21:83:24 | null | +| E.cs:83:13:83:24 | ... != ... | false | E.cs:83:21:83:24 | null | E.cs:83:13:83:16 | access to parameter vals | +| E.cs:85:18:85:29 | ... != ... | false | E.cs:85:18:85:21 | access to parameter vals | E.cs:85:26:85:29 | null | +| E.cs:85:18:85:29 | ... != ... | false | E.cs:85:26:85:29 | null | E.cs:85:18:85:21 | access to parameter vals | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:92:18:92:27 | access to constant MY_CONST_A | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:95:18:95:27 | access to constant MY_CONST_C | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:97:18:97:27 | access to constant MY_CONST_B | +| E.cs:126:21:126:29 | ... == ... | true | E.cs:126:21:126:24 | access to local variable step | E.cs:126:29:126:29 | 0 | +| E.cs:126:21:126:29 | ... == ... | true | E.cs:126:29:126:29 | 0 | E.cs:126:21:126:24 | access to local variable step | +| E.cs:153:13:153:24 | ... != ... | false | E.cs:153:13:153:16 | access to local variable obj2 | E.cs:153:21:153:24 | null | +| E.cs:153:13:153:24 | ... != ... | false | E.cs:153:21:153:24 | null | E.cs:153:13:153:16 | access to local variable obj2 | +| E.cs:164:17:164:25 | ... == ... | true | E.cs:164:17:164:17 | access to parameter a | E.cs:164:22:164:25 | null | +| E.cs:164:17:164:25 | ... == ... | true | E.cs:164:22:164:25 | null | E.cs:164:17:164:17 | access to parameter a | +| E.cs:175:19:175:29 | ... == ... | true | E.cs:175:19:175:21 | access to parameter obj | E.cs:175:26:175:29 | null | +| E.cs:175:19:175:29 | ... == ... | true | E.cs:175:26:175:29 | null | E.cs:175:19:175:21 | access to parameter obj | +| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:13:176:14 | (...) ... | E.cs:176:19:176:22 | null | +| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:19:176:22 | null | E.cs:176:13:176:14 | (...) ... | +| E.cs:180:13:180:23 | ... == ... | true | E.cs:180:13:180:15 | access to parameter obj | E.cs:180:20:180:23 | null | +| E.cs:180:13:180:23 | ... == ... | true | E.cs:180:20:180:23 | null | E.cs:180:13:180:15 | access to parameter obj | +| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:13:184:14 | (...) ... | E.cs:184:19:184:22 | null | +| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:19:184:22 | null | E.cs:184:13:184:14 | (...) ... | +| E.cs:252:13:252:21 | ... != ... | false | E.cs:252:13:252:13 | access to parameter i | E.cs:252:18:252:21 | null | +| E.cs:252:13:252:21 | ... != ... | false | E.cs:252:18:252:21 | null | E.cs:252:13:252:13 | access to parameter i | +| E.cs:259:13:259:21 | ... == ... | true | E.cs:259:13:259:13 | access to parameter i | E.cs:259:18:259:21 | null | +| E.cs:259:13:259:21 | ... == ... | true | E.cs:259:18:259:21 | null | E.cs:259:13:259: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 | +| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:35:78:38 | null | Forwarding.cs:78:32:78:32 | access to parameter o | +| Forwarding.cs:83:16:83:24 | ... != ... | false | Forwarding.cs:83:16:83:16 | access to parameter o | Forwarding.cs:83:21:83:24 | null | +| Forwarding.cs:83:16:83:24 | ... != ... | false | Forwarding.cs:83:21:83:24 | null | Forwarding.cs:83:16:83:16 | access to parameter o | +| GuardedString.cs:19:13:19:26 | ... == ... | true | GuardedString.cs:19:15:19:21 | access to property Length | GuardedString.cs:19:26:19:26 | (...) ... | +| GuardedString.cs:19:13:19:26 | ... == ... | true | GuardedString.cs:19:26:19:26 | (...) ... | GuardedString.cs:19:15:19:21 | access to property Length | +| GuardedString.cs:34:13:34:26 | ... != ... | false | GuardedString.cs:34:15:34:21 | access to property Length | GuardedString.cs:34:26:34:26 | (...) ... | +| GuardedString.cs:34:13:34:26 | ... != ... | false | GuardedString.cs:34:26:34:26 | (...) ... | GuardedString.cs:34:15:34:21 | access to property Length | +| NullAlwaysBad.cs:9:17:9:25 | ... != ... | false | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | NullAlwaysBad.cs:9:22:9:25 | null | +| NullAlwaysBad.cs:9:17:9:25 | ... != ... | false | NullAlwaysBad.cs:9:22:9:25 | null | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | +| NullAlwaysGood.cs:9:17:9:25 | ... != ... | false | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | NullAlwaysGood.cs:9:22:9:25 | null | +| NullAlwaysGood.cs:9:17:9:25 | ... != ... | false | NullAlwaysGood.cs:9:22:9:25 | null | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | +| NullMaybeGood.cs:9:17:9:25 | ... != ... | false | NullMaybeGood.cs:9:17:9:17 | access to parameter o | NullMaybeGood.cs:9:22:9:25 | null | +| NullMaybeGood.cs:9:17:9:25 | ... != ... | false | NullMaybeGood.cs:9:22:9:25 | null | NullMaybeGood.cs:9:17:9:17 | access to parameter o | +| StringConcatenation.cs:15:16:15:22 | ... != ... | false | StringConcatenation.cs:15:16:15:16 | access to local variable s | StringConcatenation.cs:15:21:15:22 | "" | +| StringConcatenation.cs:15:16:15:22 | ... != ... | false | StringConcatenation.cs:15:21:15:22 | "" | StringConcatenation.cs:15:16:15:16 | access to local variable s | +| StringConcatenation.cs:22:16:22:22 | ... != ... | false | StringConcatenation.cs:22:16:22:16 | access to local variable s | StringConcatenation.cs:22:21:22:22 | "" | +| StringConcatenation.cs:22:16:22:22 | ... != ... | false | StringConcatenation.cs:22:21:22:22 | "" | StringConcatenation.cs:22:16:22:16 | access to local variable s | diff --git a/csharp/ql/test/query-tests/Nullness/EqualityCheck.ql b/csharp/ql/test/query-tests/Nullness/EqualityCheck.ql new file mode 100644 index 00000000000..3036911b5a6 --- /dev/null +++ b/csharp/ql/test/query-tests/Nullness/EqualityCheck.ql @@ -0,0 +1,5 @@ +import csharp +import semmle.code.csharp.controlflow.Guards + +from Expr e1, AbstractValue v, Expr e2 +select Internal::getAnEqualityCheck(e1, v, e2), v, e1, e2 diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index ded9f04a903..b519fefeb39 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -80,7 +80,9 @@ | Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null | | Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | +| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:9:20:9:20 | access to parameter b | true | | Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null | +| Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:9:20:9:20 | access to parameter b | false | | Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null | | Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | @@ -106,7 +108,9 @@ | Assert.cs:21:9:21:25 | ... = ... | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | | Assert.cs:22:23:22:23 | access to local variable s | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | | Assert.cs:22:23:22:23 | access to local variable s | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | +| Assert.cs:22:23:22:31 | ... == ... | false | Assert.cs:21:13:21:13 | access to parameter b | false | | Assert.cs:22:23:22:31 | ... == ... | false | Assert.cs:22:23:22:23 | access to local variable s | non-null | +| Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:21:13:21:13 | access to parameter b | true | | Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:22:23:22:23 | access to local variable s | null | | Assert.cs:23:27:23:27 | access to local variable s | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | | Assert.cs:23:27:23:27 | access to local variable s | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | @@ -116,7 +120,9 @@ | Assert.cs:25:9:25:25 | ... = ... | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | | Assert.cs:26:23:26:23 | access to local variable s | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | | Assert.cs:26:23:26:23 | access to local variable s | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | +| Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:25:13:25:13 | access to parameter b | true | | Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:26:23:26:23 | access to local variable s | null | +| Assert.cs:26:23:26:31 | ... != ... | true | Assert.cs:25:13:25:13 | access to parameter b | false | | Assert.cs:26:23:26:31 | ... != ... | true | Assert.cs:26:23:26:23 | access to local variable s | non-null | | Assert.cs:27:27:27:27 | access to local variable s | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | | Assert.cs:27:27:27:27 | access to local variable s | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | @@ -126,7 +132,9 @@ | Assert.cs:29:9:29:25 | ... = ... | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | | Assert.cs:30:24:30:24 | access to local variable s | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | | Assert.cs:30:24:30:24 | access to local variable s | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | +| Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:29:13:29:13 | access to parameter b | true | | Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:30:24:30:24 | access to local variable s | null | +| Assert.cs:30:24:30:32 | ... != ... | true | Assert.cs:29:13:29:13 | access to parameter b | false | | Assert.cs:30:24:30:32 | ... != ... | true | Assert.cs:30:24:30:24 | access to local variable s | non-null | | Assert.cs:31:27:31:27 | access to local variable s | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | | Assert.cs:31:27:31:27 | access to local variable s | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | @@ -136,7 +144,9 @@ | Assert.cs:33:9:33:25 | ... = ... | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | | Assert.cs:34:24:34:24 | access to local variable s | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | | Assert.cs:34:24:34:24 | access to local variable s | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | +| Assert.cs:34:24:34:32 | ... == ... | false | Assert.cs:33:13:33:13 | access to parameter b | false | | Assert.cs:34:24:34:32 | ... == ... | false | Assert.cs:34:24:34:24 | access to local variable s | non-null | +| Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:33:13:33:13 | access to parameter b | true | | Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:34:24:34:24 | access to local variable s | null | | Assert.cs:35:27:35:27 | access to local variable s | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | | Assert.cs:35:27:35:27 | access to local variable s | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | @@ -146,7 +156,9 @@ | Assert.cs:37:9:37:25 | ... = ... | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | | Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | | Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | +| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:37:13:37:13 | access to parameter b | true | | Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null | +| Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:37:13:37:13 | access to parameter b | false | | Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null | | Assert.cs:38:23:38:36 | ... && ... | true | Assert.cs:38:23:38:31 | ... != ... | true | | Assert.cs:38:23:38:36 | ... && ... | true | Assert.cs:38:36:38:36 | access to parameter b | true | @@ -158,7 +170,9 @@ | Assert.cs:41:9:41:25 | ... = ... | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | | Assert.cs:42:24:42:24 | access to local variable s | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | | Assert.cs:42:24:42:24 | access to local variable s | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | +| Assert.cs:42:24:42:32 | ... == ... | false | Assert.cs:41:13:41:13 | access to parameter b | false | | Assert.cs:42:24:42:32 | ... == ... | false | Assert.cs:42:24:42:24 | access to local variable s | non-null | +| Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:41:13:41:13 | access to parameter b | true | | Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:42:24:42:24 | access to local variable s | null | | Assert.cs:42:24:42:37 | ... \|\| ... | false | Assert.cs:42:24:42:32 | ... == ... | false | | Assert.cs:42:24:42:37 | ... \|\| ... | false | Assert.cs:42:37:42:37 | access to parameter b | false | @@ -170,7 +184,9 @@ | Assert.cs:45:9:45:25 | ... = ... | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | | Assert.cs:46:23:46:23 | access to local variable s | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | | Assert.cs:46:23:46:23 | access to local variable s | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | +| Assert.cs:46:23:46:31 | ... == ... | false | Assert.cs:45:13:45:13 | access to parameter b | false | | Assert.cs:46:23:46:31 | ... == ... | false | Assert.cs:46:23:46:23 | access to local variable s | non-null | +| Assert.cs:46:23:46:31 | ... == ... | true | Assert.cs:45:13:45:13 | access to parameter b | true | | Assert.cs:46:23:46:31 | ... == ... | true | Assert.cs:46:23:46:23 | access to local variable s | null | | Assert.cs:46:23:46:36 | ... && ... | true | Assert.cs:46:23:46:31 | ... == ... | true | | Assert.cs:46:23:46:36 | ... && ... | true | Assert.cs:46:36:46:36 | access to parameter b | true | @@ -182,7 +198,9 @@ | Assert.cs:49:9:49:25 | ... = ... | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | | Assert.cs:50:24:50:24 | access to local variable s | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | | Assert.cs:50:24:50:24 | access to local variable s | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | +| Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:49:13:49:13 | access to parameter b | true | | Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:24:50:24 | access to local variable s | null | +| Assert.cs:50:24:50:32 | ... != ... | true | Assert.cs:49:13:49:13 | access to parameter b | false | | Assert.cs:50:24:50:32 | ... != ... | true | Assert.cs:50:24:50:24 | access to local variable s | non-null | | Assert.cs:50:24:50:37 | ... \|\| ... | false | Assert.cs:50:24:50:32 | ... != ... | false | | Assert.cs:50:24:50:37 | ... \|\| ... | false | Assert.cs:50:37:50:37 | access to parameter b | false | @@ -276,7 +294,9 @@ | C.cs:40:13:40:35 | String s = ... | null | C.cs:40:13:40:13 | access to local variable s | null | | C.cs:41:22:41:22 | access to local variable s | non-null | C.cs:40:17:40:35 | ... ? ... : ... | non-null | | C.cs:41:22:41:22 | access to local variable s | null | C.cs:40:17:40:35 | ... ? ... : ... | null | +| C.cs:41:22:41:30 | ... == ... | false | C.cs:40:17:40:23 | call to method Maybe | false | | C.cs:41:22:41:30 | ... == ... | false | C.cs:41:22:41:22 | access to local variable s | non-null | +| C.cs:41:22:41:30 | ... == ... | true | C.cs:40:17:40:23 | call to method Maybe | true | | C.cs:41:22:41:30 | ... == ... | true | C.cs:41:22:41:22 | access to local variable s | null | | C.cs:42:9:42:9 | access to local variable s | non-null | C.cs:40:17:40:35 | ... ? ... : ... | non-null | | C.cs:42:9:42:9 | access to local variable s | null | C.cs:40:17:40:35 | ... ? ... : ... | null | @@ -286,7 +306,9 @@ | C.cs:44:9:44:31 | ... = ... | null | C.cs:44:13:44:31 | ... ? ... : ... | null | | C.cs:45:22:45:22 | access to local variable s | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | | C.cs:45:22:45:22 | access to local variable s | null | C.cs:44:13:44:31 | ... ? ... : ... | null | +| C.cs:45:22:45:30 | ... != ... | false | C.cs:44:13:44:19 | call to method Maybe | true | | C.cs:45:22:45:30 | ... != ... | false | C.cs:45:22:45:22 | access to local variable s | null | +| C.cs:45:22:45:30 | ... != ... | true | C.cs:44:13:44:19 | call to method Maybe | false | | C.cs:45:22:45:30 | ... != ... | true | C.cs:45:22:45:22 | access to local variable s | non-null | | C.cs:46:9:46:9 | access to local variable s | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | | C.cs:46:9:46:9 | access to local variable s | null | C.cs:44:13:44:31 | ... ? ... : ... | null | @@ -491,7 +513,9 @@ | C.cs:211:13:211:35 | String s = ... | null | C.cs:211:13:211:13 | access to local variable s | null | | C.cs:212:13:212:13 | access to local variable s | non-null | C.cs:211:17:211:35 | ... ? ... : ... | non-null | | C.cs:212:13:212:13 | access to local variable s | null | C.cs:211:17:211:35 | ... ? ... : ... | null | +| C.cs:212:13:212:21 | ... != ... | false | C.cs:211:17:211:23 | call to method Maybe | true | | C.cs:212:13:212:21 | ... != ... | false | C.cs:212:13:212:13 | access to local variable s | null | +| C.cs:212:13:212:21 | ... != ... | true | C.cs:211:17:211:23 | call to method Maybe | false | | C.cs:212:13:212:21 | ... != ... | true | C.cs:212:13:212:13 | access to local variable s | non-null | | C.cs:214:13:214:13 | access to local variable s | non-null | C.cs:211:17:211:35 | ... ? ... : ... | non-null | | C.cs:214:13:214:13 | access to local variable s | null | C.cs:211:17:211:35 | ... ? ... : ... | null | @@ -499,6 +523,7 @@ | C.cs:215:13:215:20 | ... = ... | non-null | C.cs:215:17:215:20 | null | non-null | | C.cs:215:13:215:20 | ... = ... | null | C.cs:215:13:215:13 | access to local variable s | null | | C.cs:215:13:215:20 | ... = ... | null | C.cs:215:17:215:20 | null | null | +| C.cs:218:13:218:21 | ... == ... | false | C.cs:212:13:212:21 | ... != ... | false | | C.cs:218:13:218:21 | ... == ... | false | C.cs:218:13:218:13 | access to local variable s | non-null | | C.cs:218:13:218:21 | ... == ... | true | C.cs:218:13:218:13 | access to local variable s | null | | C.cs:221:9:221:14 | ... = ... | non-null | C.cs:221:9:221:9 | access to local variable s | non-null | @@ -590,7 +615,9 @@ | D.cs:44:13:44:44 | Object o1 = ... | null | D.cs:44:13:44:14 | access to local variable o1 | null | | D.cs:45:13:45:14 | access to local variable o1 | non-null | D.cs:44:18:44:44 | ... ? ... : ... | non-null | | D.cs:45:13:45:14 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | +| D.cs:45:13:45:22 | ... != ... | false | D.cs:44:18:44:22 | access to field maybe | true | | D.cs:45:13:45:22 | ... != ... | false | D.cs:45:13:45:14 | access to local variable o1 | null | +| D.cs:45:13:45:22 | ... != ... | true | D.cs:44:18:44:22 | access to field maybe | false | | D.cs:45:13:45:22 | ... != ... | true | D.cs:45:13:45:14 | access to local variable o1 | non-null | | D.cs:45:25:45:26 | access to local variable o1 | non-null | D.cs:44:18:44:44 | ... ? ... : ... | non-null | | D.cs:45:25:45:26 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | @@ -598,7 +625,9 @@ | D.cs:47:13:47:34 | String o2 = ... | null | D.cs:47:13:47:14 | access to local variable o2 | null | | D.cs:48:13:48:14 | access to local variable o2 | non-null | D.cs:47:18:47:34 | ... ? ... : ... | non-null | | D.cs:48:13:48:14 | access to local variable o2 | null | D.cs:47:18:47:34 | ... ? ... : ... | null | +| D.cs:48:13:48:24 | ... is ... | false | D.cs:47:18:47:22 | access to field maybe | true | | D.cs:48:13:48:24 | ... is ... | false | D.cs:48:13:48:14 | access to local variable o2 | null | +| D.cs:48:13:48:24 | ... is ... | true | D.cs:47:18:47:22 | access to field maybe | false | | D.cs:48:13:48:24 | ... is ... | true | D.cs:48:13:48:14 | access to local variable o2 | non-null | | D.cs:48:27:48:28 | access to local variable o2 | non-null | D.cs:47:18:47:34 | ... ? ... : ... | non-null | | D.cs:48:27:48:28 | access to local variable o2 | null | D.cs:47:18:47:34 | ... ? ... : ... | null | @@ -620,7 +649,9 @@ | D.cs:55:14:55:32 | ... && ... | true | D.cs:55:23:55:32 | ... != ... | true | | D.cs:55:23:55:24 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:55:23:55:24 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:55:23:55:32 | ... != ... | false | D.cs:54:18:54:22 | access to field maybe | true | | D.cs:55:23:55:32 | ... != ... | false | D.cs:55:23:55:24 | access to local variable o4 | null | +| D.cs:55:23:55:32 | ... != ... | true | D.cs:54:18:54:22 | access to field maybe | false | | D.cs:55:23:55:32 | ... != ... | true | D.cs:55:23:55:24 | access to local variable o4 | non-null | | D.cs:56:13:56:14 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:56:13:56:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | @@ -628,17 +659,23 @@ | D.cs:58:13:58:41 | String o5 = ... | null | D.cs:58:13:58:14 | access to local variable o5 | null | | D.cs:58:19:58:20 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:58:19:58:20 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:58:19:58:28 | ... != ... | false | D.cs:54:18:54:22 | access to field maybe | true | | D.cs:58:19:58:28 | ... != ... | false | D.cs:58:19:58:20 | access to local variable o4 | null | +| D.cs:58:19:58:28 | ... != ... | true | D.cs:54:18:54:22 | access to field maybe | false | | D.cs:58:19:58:28 | ... != ... | true | D.cs:58:19:58:20 | access to local variable o4 | non-null | | D.cs:59:13:59:14 | access to local variable o5 | non-null | D.cs:58:18:58:41 | ... ? ... : ... | non-null | | D.cs:59:13:59:14 | access to local variable o5 | null | D.cs:58:18:58:41 | ... ? ... : ... | null | +| D.cs:59:13:59:22 | ... != ... | false | D.cs:58:19:58:28 | ... != ... | false | | D.cs:59:13:59:22 | ... != ... | false | D.cs:59:13:59:14 | access to local variable o5 | null | +| D.cs:59:13:59:22 | ... != ... | true | D.cs:58:19:58:28 | ... != ... | true | | D.cs:59:13:59:22 | ... != ... | true | D.cs:59:13:59:14 | access to local variable o5 | non-null | | D.cs:60:13:60:14 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:60:13:60:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | | D.cs:61:13:61:14 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:61:13:61:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | +| D.cs:61:13:61:22 | ... != ... | false | D.cs:54:18:54:22 | access to field maybe | true | | D.cs:61:13:61:22 | ... != ... | false | D.cs:61:13:61:14 | access to local variable o4 | null | +| D.cs:61:13:61:22 | ... != ... | true | D.cs:54:18:54:22 | access to field maybe | false | | D.cs:61:13:61:22 | ... != ... | true | D.cs:61:13:61:14 | access to local variable o4 | non-null | | D.cs:62:13:62:14 | access to local variable o5 | non-null | D.cs:58:18:58:41 | ... ? ... : ... | non-null | | D.cs:62:13:62:14 | access to local variable o5 | null | D.cs:58:18:58:41 | ... ? ... : ... | null | @@ -646,7 +683,9 @@ | D.cs:64:13:64:34 | String o6 = ... | null | D.cs:64:13:64:14 | access to local variable o6 | null | | D.cs:65:13:65:29 | !... | false | D.cs:65:14:65:29 | call to method CustomIsNull | true | | D.cs:65:13:65:29 | !... | true | D.cs:65:14:65:29 | call to method CustomIsNull | false | +| D.cs:65:14:65:29 | call to method CustomIsNull | false | D.cs:64:18:64:22 | access to field maybe | false | | D.cs:65:14:65:29 | call to method CustomIsNull | false | D.cs:65:27:65:28 | access to local variable o6 | non-null | +| D.cs:65:14:65:29 | call to method CustomIsNull | true | D.cs:64:18:64:22 | access to field maybe | true | | D.cs:65:14:65:29 | call to method CustomIsNull | true | D.cs:65:27:65:28 | access to local variable o6 | null | | D.cs:65:27:65:28 | access to local variable o6 | non-null | D.cs:64:18:64:34 | ... ? ... : ... | non-null | | D.cs:65:27:65:28 | access to local variable o6 | null | D.cs:64:18:64:34 | ... ? ... : ... | null | @@ -658,7 +697,9 @@ | D.cs:69:13:69:36 | Boolean ok = ... | true | D.cs:69:13:69:14 | access to local variable ok | true | | D.cs:69:18:69:19 | access to local variable o7 | non-null | D.cs:68:18:68:34 | ... ? ... : ... | non-null | | D.cs:69:18:69:19 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | +| D.cs:69:18:69:27 | ... != ... | false | D.cs:68:18:68:22 | access to field maybe | true | | D.cs:69:18:69:27 | ... != ... | false | D.cs:69:18:69:19 | access to local variable o7 | null | +| D.cs:69:18:69:27 | ... != ... | true | D.cs:68:18:68:22 | access to field maybe | false | | D.cs:69:18:69:27 | ... != ... | true | D.cs:69:18:69:19 | access to local variable o7 | non-null | | D.cs:69:18:69:36 | ... && ... | true | D.cs:69:18:69:27 | ... != ... | true | | D.cs:69:18:69:36 | ... && ... | true | D.cs:69:32:69:36 | ... > ... | true | @@ -672,7 +713,9 @@ | D.cs:75:13:75:34 | String o8 = ... | null | D.cs:75:13:75:14 | access to local variable o8 | null | | D.cs:76:21:76:22 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:76:21:76:22 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:76:21:76:30 | ... == ... | false | D.cs:75:18:75:22 | access to field maybe | false | | D.cs:76:21:76:30 | ... == ... | false | D.cs:76:21:76:22 | access to local variable o8 | non-null | +| D.cs:76:21:76:30 | ... == ... | true | D.cs:75:18:75:22 | access to field maybe | true | | D.cs:76:21:76:30 | ... == ... | true | D.cs:76:21:76:22 | access to local variable o8 | null | | D.cs:78:13:78:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:78:13:78:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | @@ -704,7 +747,9 @@ | D.cs:106:17:106:18 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | | D.cs:110:26:110:27 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | | D.cs:110:26:110:27 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | +| D.cs:110:26:110:35 | ... != ... | false | D.cs:89:20:89:24 | access to field maybe | true | | D.cs:110:26:110:35 | ... != ... | false | D.cs:110:26:110:27 | access to local variable xs | null | +| D.cs:110:26:110:35 | ... != ... | true | D.cs:89:20:89:24 | access to field maybe | false | | D.cs:110:26:110:35 | ... != ... | true | D.cs:110:26:110:27 | access to local variable xs | non-null | | D.cs:111:13:111:14 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | | D.cs:111:13:111:14 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | @@ -718,13 +763,16 @@ | D.cs:118:9:118:30 | ... = ... | null | D.cs:118:13:118:30 | ... ? ... : ... | null | | D.cs:118:13:118:13 | access to local variable x | non-null | D.cs:117:17:117:32 | ... ? ... : ... | non-null | | D.cs:118:13:118:13 | access to local variable x | null | D.cs:117:17:117:32 | ... ? ... : ... | null | +| D.cs:118:13:118:21 | ... == ... | false | D.cs:117:17:117:17 | access to parameter b | false | | D.cs:118:13:118:21 | ... == ... | false | D.cs:118:13:118:13 | access to local variable x | non-null | +| D.cs:118:13:118:21 | ... == ... | true | D.cs:117:17:117:17 | access to parameter b | true | | D.cs:118:13:118:21 | ... == ... | true | D.cs:118:13:118:13 | access to local variable x | null | | D.cs:118:30:118:30 | access to local variable x | non-null | D.cs:117:17:117:32 | ... ? ... : ... | non-null | | D.cs:118:30:118:30 | access to local variable x | null | D.cs:117:17:117:32 | ... ? ... : ... | null | | D.cs:119:13:119:13 | access to local variable x | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | | D.cs:119:13:119:13 | access to local variable x | null | D.cs:118:13:118:30 | ... ? ... : ... | null | | D.cs:119:13:119:21 | ... == ... | false | D.cs:119:13:119:13 | access to local variable x | non-null | +| D.cs:119:13:119:21 | ... == ... | true | D.cs:118:13:118:21 | ... == ... | false | | D.cs:119:13:119:21 | ... == ... | true | D.cs:119:13:119:13 | access to local variable x | null | | D.cs:120:13:120:13 | access to local variable x | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | | D.cs:120:13:120:13 | access to local variable x | null | D.cs:118:13:118:30 | ... ? ... : ... | null | @@ -827,7 +875,9 @@ | D.cs:241:13:241:37 | String other = ... | null | D.cs:241:13:241:17 | access to local variable other | null | | D.cs:242:13:242:17 | access to local variable other | non-null | D.cs:241:21:241:37 | ... ? ... : ... | non-null | | D.cs:242:13:242:17 | access to local variable other | null | D.cs:241:21:241:37 | ... ? ... : ... | null | +| D.cs:242:13:242:25 | ... == ... | false | D.cs:241:21:241:25 | access to field maybe | false | | D.cs:242:13:242:25 | ... == ... | false | D.cs:242:13:242:17 | access to local variable other | non-null | +| D.cs:242:13:242:25 | ... == ... | true | D.cs:241:21:241:25 | access to field maybe | true | | D.cs:242:13:242:25 | ... == ... | true | D.cs:242:13:242:17 | access to local variable other | null | | D.cs:243:13:243:18 | ... = ... | non-null | D.cs:243:13:243:13 | access to local variable o | non-null | | D.cs:243:13:243:18 | ... = ... | non-null | D.cs:243:17:243:18 | "" | non-null | @@ -835,7 +885,9 @@ | D.cs:243:13:243:18 | ... = ... | null | D.cs:243:17:243:18 | "" | null | | D.cs:244:13:244:17 | access to local variable other | non-null | D.cs:241:21:241:37 | ... ? ... : ... | non-null | | D.cs:244:13:244:17 | access to local variable other | null | D.cs:241:21:241:37 | ... ? ... : ... | null | +| D.cs:244:13:244:25 | ... != ... | false | D.cs:241:21:241:25 | access to field maybe | true | | D.cs:244:13:244:25 | ... != ... | false | D.cs:244:13:244:17 | access to local variable other | null | +| D.cs:244:13:244:25 | ... != ... | true | D.cs:241:21:241:25 | access to field maybe | false | | D.cs:244:13:244:25 | ... != ... | true | D.cs:244:13:244:17 | access to local variable other | non-null | | D.cs:249:13:249:38 | String o2 = ... | non-null | D.cs:249:13:249:14 | access to local variable o2 | non-null | | D.cs:249:13:249:38 | String o2 = ... | null | D.cs:249:13:249:14 | access to local variable o2 | null | @@ -917,6 +969,7 @@ | D.cs:339:13:339:23 | ... = ... | non-null | D.cs:339:19:339:23 | "bar" | non-null | | D.cs:339:13:339:23 | ... = ... | null | D.cs:339:13:339:15 | access to local variable msg | null | | D.cs:339:13:339:23 | ... = ... | null | D.cs:339:19:339:23 | "bar" | null | +| D.cs:341:13:341:23 | ... != ... | false | D.cs:336:13:336:23 | ... == ... | false | | D.cs:341:13:341:23 | ... != ... | false | D.cs:341:13:341:15 | access to local variable msg | null | | D.cs:341:13:341:23 | ... != ... | true | D.cs:341:13:341:15 | access to local variable msg | non-null | | D.cs:343:13:343:27 | ... + ... | non-null | D.cs:343:13:343:15 | access to local variable msg | non-null | @@ -948,7 +1001,9 @@ | D.cs:367:13:367:56 | ... && ... | true | D.cs:367:27:367:55 | ... \|\| ... | true | | D.cs:367:27:367:27 | access to local variable b | non-null | D.cs:366:19:366:47 | ... ? ... : ... | non-null | | D.cs:367:27:367:27 | access to local variable b | null | D.cs:366:19:366:47 | ... ? ... : ... | null | +| D.cs:367:27:367:35 | ... == ... | false | D.cs:366:19:366:23 | access to field maybe | false | | D.cs:367:27:367:35 | ... == ... | false | D.cs:367:27:367:27 | access to local variable b | non-null | +| D.cs:367:27:367:35 | ... == ... | true | D.cs:366:19:366:23 | access to field maybe | true | | D.cs:367:27:367:35 | ... == ... | true | D.cs:367:27:367:27 | access to local variable b | null | | D.cs:367:27:367:55 | ... \|\| ... | false | D.cs:367:27:367:35 | ... == ... | false | | D.cs:367:27:367:55 | ... \|\| ... | false | D.cs:367:40:367:55 | ... < ... | false | @@ -962,6 +1017,7 @@ | D.cs:380:13:380:35 | ... = ... | non-null | D.cs:380:19:380:35 | object creation of type Exception | non-null | | D.cs:380:13:380:35 | ... = ... | null | D.cs:380:13:380:15 | access to local variable ioe | null | | D.cs:380:13:380:35 | ... = ... | null | D.cs:380:19:380:35 | object creation of type Exception | null | +| D.cs:382:13:382:23 | ... != ... | false | D.cs:379:13:379:13 | access to parameter b | false | | D.cs:382:13:382:23 | ... != ... | false | D.cs:382:13:382:15 | access to local variable ioe | null | | D.cs:382:13:382:23 | ... != ... | true | D.cs:382:13:382:15 | access to local variable ioe | non-null | | D.cs:383:13:383:19 | ... = ... | non-null | D.cs:383:13:383:15 | access to local variable ioe | non-null | @@ -1024,11 +1080,15 @@ | E.cs:20:13:20:41 | String s2 = ... | null | E.cs:20:13:20:14 | access to local variable s2 | null | | E.cs:20:19:20:20 | access to local variable s1 | non-null | E.cs:19:18:19:30 | ... ? ... : ... | non-null | | E.cs:20:19:20:20 | access to local variable s1 | null | E.cs:19:18:19:30 | ... ? ... : ... | null | +| E.cs:20:19:20:28 | ... == ... | false | E.cs:19:18:19:18 | access to parameter x | false | | E.cs:20:19:20:28 | ... == ... | false | E.cs:20:19:20:20 | access to local variable s1 | non-null | +| E.cs:20:19:20:28 | ... == ... | true | E.cs:19:18:19:18 | access to parameter x | true | | E.cs:20:19:20:28 | ... == ... | true | E.cs:20:19:20:20 | access to local variable s1 | null | | E.cs:21:13:21:14 | access to local variable s2 | non-null | E.cs:20:18:20:41 | ... ? ... : ... | non-null | | E.cs:21:13:21:14 | access to local variable s2 | null | E.cs:20:18:20:41 | ... ? ... : ... | null | +| E.cs:21:13:21:22 | ... == ... | false | E.cs:20:19:20:28 | ... == ... | false | | E.cs:21:13:21:22 | ... == ... | false | E.cs:21:13:21:14 | access to local variable s2 | non-null | +| E.cs:21:13:21:22 | ... == ... | true | E.cs:20:19:20:28 | ... == ... | true | | E.cs:21:13:21:22 | ... == ... | true | E.cs:21:13:21:14 | access to local variable s2 | null | | E.cs:23:13:23:30 | ... = ... | non-null | E.cs:23:13:23:14 | access to local variable s1 | non-null | | E.cs:23:13:23:30 | ... = ... | non-null | E.cs:23:18:23:30 | ... ? ... : ... | non-null | @@ -1040,7 +1100,9 @@ | E.cs:24:13:24:41 | ... = ... | null | E.cs:24:18:24:41 | ... ? ... : ... | null | | E.cs:24:19:24:20 | access to local variable s1 | non-null | E.cs:23:18:23:30 | ... ? ... : ... | non-null | | E.cs:24:19:24:20 | access to local variable s1 | null | E.cs:23:18:23:30 | ... ? ... : ... | null | +| E.cs:24:19:24:28 | ... == ... | false | E.cs:23:18:23:18 | access to parameter y | false | | E.cs:24:19:24:28 | ... == ... | false | E.cs:24:19:24:20 | access to local variable s1 | non-null | +| E.cs:24:19:24:28 | ... == ... | true | E.cs:23:18:23:18 | access to parameter y | true | | E.cs:24:19:24:28 | ... == ... | true | E.cs:24:19:24:20 | access to local variable s1 | null | | E.cs:26:13:26:22 | ... != ... | false | E.cs:26:13:26:14 | access to local variable s2 | null | | E.cs:26:13:26:22 | ... != ... | true | E.cs:26:13:26:14 | access to local variable s2 | non-null | @@ -1271,6 +1333,7 @@ | GuardedString.cs:7:16:7:32 | String s = ... | null | GuardedString.cs:7:16:7:16 | access to local variable s | null | | GuardedString.cs:9:13:9:36 | !... | false | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | true | | GuardedString.cs:9:13:9:36 | !... | true | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | +| GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | GuardedString.cs:9:35:9:35 | access to local variable s | non-null | | GuardedString.cs:9:35:9:35 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:9:35:9:35 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | @@ -1278,47 +1341,60 @@ | GuardedString.cs:11:31:11:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:14:13:14:41 | !... | false | GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | true | | GuardedString.cs:14:13:14:41 | !... | true | GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | false | +| GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | false | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | false | GuardedString.cs:14:40:14:40 | access to local variable s | non-null | | GuardedString.cs:14:40:14:40 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:14:40:14:40 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:16:31:16:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:16:31:16:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:19:13:19:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:19:13:19:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:19:13:19:13 | access to local variable s | null | GuardedString.cs:7:20:7:20 | access to parameter b | true | | GuardedString.cs:19:13:19:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:19:13:19:26 | ... == ... | true | GuardedString.cs:19:15:19:21 | access to property Length | non-null | | GuardedString.cs:19:15:19:21 | access to property Length | non-null | GuardedString.cs:19:13:19:13 | access to local variable s | non-null | | GuardedString.cs:19:15:19:21 | access to property Length | null | GuardedString.cs:19:13:19:13 | access to local variable s | null | | GuardedString.cs:20:31:20:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:20:31:20:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:22:13:22:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:22:13:22:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:22:13:22:13 | access to local variable s | null | GuardedString.cs:7:20:7:20 | access to parameter b | true | | GuardedString.cs:22:13:22:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:22:13:22:25 | ... > ... | true | GuardedString.cs:22:15:22:21 | access to property Length | non-null | | GuardedString.cs:22:15:22:21 | access to property Length | non-null | GuardedString.cs:22:13:22:13 | access to local variable s | non-null | | GuardedString.cs:22:15:22:21 | access to property Length | null | GuardedString.cs:22:13:22:13 | access to local variable s | null | | GuardedString.cs:23:31:23:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:23:31:23:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:25:13:25:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:25:13:25:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:25:13:25:13 | access to local variable s | null | GuardedString.cs:7:20:7:20 | access to parameter b | true | | GuardedString.cs:25:13:25:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:25:13:25:26 | ... >= ... | true | GuardedString.cs:25:15:25:21 | access to property Length | non-null | | GuardedString.cs:25:15:25:21 | access to property Length | non-null | GuardedString.cs:25:13:25:13 | access to local variable s | non-null | | GuardedString.cs:25:15:25:21 | access to property Length | null | GuardedString.cs:25:13:25:13 | access to local variable s | null | | GuardedString.cs:26:31:26:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:26:31:26:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:28:13:28:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:28:13:28:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:28:13:28:13 | access to local variable s | null | GuardedString.cs:7:20:7:20 | access to parameter b | true | | GuardedString.cs:28:13:28:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:28:13:28:26 | ... < ... | true | GuardedString.cs:28:15:28:21 | access to property Length | non-null | | GuardedString.cs:28:15:28:21 | access to property Length | non-null | GuardedString.cs:28:13:28:13 | access to local variable s | non-null | | GuardedString.cs:28:15:28:21 | access to property Length | null | GuardedString.cs:28:13:28:13 | access to local variable s | null | | GuardedString.cs:29:31:29:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:29:31:29:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:31:13:31:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:31:13:31:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:31:13:31:13 | access to local variable s | null | GuardedString.cs:7:20:7:20 | access to parameter b | true | | GuardedString.cs:31:13:31:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:31:13:31:27 | ... <= ... | true | GuardedString.cs:31:15:31:21 | access to property Length | non-null | | GuardedString.cs:31:15:31:21 | access to property Length | non-null | GuardedString.cs:31:13:31:13 | access to local variable s | non-null | | GuardedString.cs:31:15:31:21 | access to property Length | null | GuardedString.cs:31:13:31:13 | access to local variable s | null | | GuardedString.cs:32:31:32:31 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | | GuardedString.cs:32:31:32:31 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | +| GuardedString.cs:34:13:34:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:20 | access to parameter b | false | | GuardedString.cs:34:13:34:13 | access to local variable s | non-null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | +| GuardedString.cs:34:13:34:13 | access to local variable s | null | GuardedString.cs:7:20:7:20 | access to parameter b | true | | GuardedString.cs:34:13:34:13 | access to local variable s | null | GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | | GuardedString.cs:34:13:34:26 | ... != ... | false | GuardedString.cs:34:15:34:21 | access to property Length | non-null | | GuardedString.cs:34:15:34:21 | access to property Length | non-null | GuardedString.cs:34:13:34:13 | access to local variable s | non-null | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index f3bea25a6d1..9a58ca9330c 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -8,7 +8,6 @@ | C.cs:243:13:243:13 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:229:16:229:16 | s | s | C.cs:241:24:241:31 | ... = ... | this | | D.cs:23:9:23:13 | access to parameter param | Variable '$@' may be null here because of $@ null argument. | D.cs:21:32:21:36 | param | param | D.cs:17:17:17:20 | null | this | | D.cs:32:9:32:13 | access to parameter param | Variable '$@' may be null here as suggested by $@ null check. | D.cs:26:32:26:36 | param | param | D.cs:28:13:28:25 | ... != ... | this | -| D.cs:60:13:60:14 | access to local variable o4 | Variable '$@' may be null here because of $@ assignment. | D.cs:54:13:54:14 | o4 | o4 | D.cs:54:13:54:34 | String o4 = ... | this | | D.cs:62:13:62:14 | access to local variable o5 | Variable '$@' may be null here because of $@ assignment. | D.cs:58:13:58:14 | o5 | o5 | D.cs:58:13:58:41 | String o5 = ... | this | | D.cs:73:13:73:14 | access to local variable o7 | Variable '$@' may be null here because of $@ assignment. | D.cs:68:13:68:14 | o7 | o7 | D.cs:68:13:68:34 | String o7 = ... | this | | D.cs:78:13:78:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | @@ -38,7 +37,6 @@ | D.cs:300:17:300:20 | access to local variable prev | Variable '$@' may be null here because of $@ assignment. | D.cs:296:16:296:19 | prev | prev | D.cs:296:16:296:26 | Object prev = ... | this | | D.cs:313:17:313:17 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | D.cs:304:16:304:16 | s | s | D.cs:304:16:304:23 | String s = ... | this | | D.cs:324:9:324:9 | access to local variable r | Variable '$@' may be null here because of $@ assignment. | D.cs:316:16:316:16 | r | r | D.cs:316:16:316:23 | Object r = ... | this | -| D.cs:346:9:346:11 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | D.cs:333:26:333:28 | obj | obj | D.cs:336:13:336:23 | ... == ... | this | | D.cs:356:13:356:13 | access to local variable a | Variable '$@' may be null here because of $@ assignment. | D.cs:351:15:351:15 | a | a | D.cs:351:15:351:22 | Int32[] a = ... | this | | D.cs:363:13:363:16 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | D.cs:360:20:360:23 | last | last | D.cs:360:20:360:30 | String last = ... | this | | D.cs:372:13:372:13 | access to local variable b | Variable '$@' may be null here because of $@ assignment. | D.cs:366:15:366:15 | b | b | D.cs:366:15:366:47 | Int32[] b = ... | this | @@ -52,7 +50,6 @@ | D.cs:412:13:412:13 | access to parameter x | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:409:13:409:21 | ... != ... | this | | E.cs:12:38:12:39 | access to local variable a2 | Variable '$@' may be null here because of $@ assignment. | E.cs:9:18:9:19 | a2 | a2 | E.cs:9:18:9:26 | Int64[][] a2 = ... | this | | E.cs:14:13:14:14 | access to local variable a3 | Variable '$@' may be null here because of $@ assignment. | E.cs:11:16:11:17 | a3 | a3 | E.cs:11:16:11:24 | Int64[] a3 = ... | this | -| E.cs:27:13:27:14 | access to local variable s1 | Variable '$@' may be null here because of $@ assignment. | E.cs:19:13:19:14 | s1 | s1 | E.cs:19:13:19:30 | String s1 = ... | this | | E.cs:27:13:27:14 | access to local variable s1 | Variable '$@' may be null here because of $@ assignment. | E.cs:19:13:19:14 | s1 | s1 | E.cs:23:13:23:30 | ... = ... | this | | E.cs:35:9:35:12 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:32:16:32:26 | String last = ... | this | | E.cs:43:13:43:16 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:37:9:37:19 | ... = ... | this | From 3b0d1599adf52bebec0be5c5f82dd20d584c6c35 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 14 Nov 2018 20:16:20 +0100 Subject: [PATCH 4/8] C#: Teach guards library about unique assignments For example, in ``` void M(object x) { var y = x == null ? 1 : 2; if (y == 2) x.ToString(); } ``` the guard `y == 2` implies that the guard `x == null` must be false, as the assignment of `2` to `y` is unique. --- .../semmle/code/csharp/controlflow/Guards.qll | 85 +++++++++++++++++++ csharp/ql/test/query-tests/Nullness/D.cs | 2 +- csharp/ql/test/query-tests/Nullness/E.cs | 4 +- .../Nullness/Implications.expected | 6 ++ .../query-tests/Nullness/NullMaybe.expected | 5 -- 5 files changed, 94 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index be85ae0c542..f55e7836dfe 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -980,6 +980,82 @@ module Internal { ) } + /** + * Holds if `def` can have a value that is not representable as an + * abstract value. + */ + private predicate hasPossibleUnknownValue(PreSsa::Definition def) { + exists(PreSsa::Definition input | + input = def.getAPhiInput*() and + not exists(input.getAPhiInput()) + | + not exists(input.getDefinition().getSource()) + or + exists(Expr e | + e = stripConditionalExpr(input.getDefinition().getSource()) | + not e = any(AbstractValue v).getAnExpr() + ) + ) + } + + /** + * Gets an ultimate definition of `def` that is not itself a phi node. The + * boolean `fromBackEdge` indicates whether the flow from `result` to `def` + * goes through a back edge. + */ + PreSsa::Definition getADefinition(PreSsa::Definition def, boolean fromBackEdge) { + result = def and + not exists(def.getAPhiInput()) and + fromBackEdge = false + or + exists(PreSsa::Definition input, PreBasicBlocks::PreBasicBlock pred, boolean fbe | + input = def.getAPhiInput() | + pred = def.getBasicBlock().getAPredecessor() and + PreSsa::ssaDefReachesEndOfBlock(pred, input, _) and + result = getADefinition(input, fbe) and + (if def.getBasicBlock().dominates(pred) then fromBackEdge = true else fromBackEdge = fbe) + ) + } + + /** + * Holds if `e` has abstract value `v` and may be assigned to `def`. The Boolean + * `fromBackEdge` indicates whether the flow from `e` to `def` goes through a + * back edge. + */ + private predicate possibleValue(PreSsa::Definition def, boolean fromBackEdge, Expr e, AbstractValue v) { + not hasPossibleUnknownValue(def) and + exists(PreSsa::Definition input | + input = getADefinition(def, fromBackEdge) | + e = stripConditionalExpr(input.getDefinition().getSource()) and + v.getAnExpr() = e + ) + } + + private predicate nonUniqueValue(PreSsa::Definition def, Expr e, AbstractValue v) { + possibleValue(def, false, e, v) and + possibleValue(def, _, any(Expr other | other != e), v) + } + + /** + * Holds if `e` has abstract value `v` and may be assigned to `def` without going + * through back edges, and all other possible ultimate definitions of `def` do not + * have abstract value `v`. The trivial case where `def` is an explicit update with + * source `e is excluded. + */ + private predicate uniqueValue(PreSsa::Definition def, Expr e, AbstractValue v) { + possibleValue(def, false, e, v) and + not nonUniqueValue(def, e, v) and + exists(Expr other | possibleValue(def, _, other, _) and other != e) + } + + /** + * Holds if `guard` having abstract value `vGuard` implies that `def` has + * abstract value `vDef`. + */ + private predicate guardImpliesEqual(Guard guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) { + guard = getAnEqualityCheck(def.getARead(), vGuard, vDef.getAnExpr()) + } + /** * A helper class for calculating structurally equal access/call expressions. */ @@ -1167,6 +1243,15 @@ module Internal { conditionalAssignVal(g2, v2.getDualValue(), def, v) and guardImpliesNotEqual(g1, v1, def, v) ) + or + exists(PreSsa::Definition def, Expr e, AbstractValue v | + // If `def = g2 ? v : ...` and all other assignments to `def` are different from + // `v` then a guard proving `def == v` ensures that `g2` evaluates to `v2`. + uniqueValue(def, e, v) and + guardImpliesEqual(g1, v1, def, v) and + g2.preControlsDirect(any(PreBasicBlocks::PreBasicBlock bb | e = bb.getAnElement()), v2) and + not g2.preControlsDirect(any(PreBasicBlocks::PreBasicBlock bb | g1 = bb.getAnElement()), v2) + ) } cached diff --git a/csharp/ql/test/query-tests/Nullness/D.cs b/csharp/ql/test/query-tests/Nullness/D.cs index ae0563ad813..bc2aab77cac 100644 --- a/csharp/ql/test/query-tests/Nullness/D.cs +++ b/csharp/ql/test/query-tests/Nullness/D.cs @@ -75,7 +75,7 @@ public class D var o8 = maybe ? null : ""; int track = o8 == null ? 42 : 1 + 1; if (track == 2) - o8.ToString(); // GOOD (false positive) + o8.ToString(); // GOOD if (track != 42) o8.ToString(); // GOOD (false positive) if (track < 42) diff --git a/csharp/ql/test/query-tests/Nullness/E.cs b/csharp/ql/test/query-tests/Nullness/E.cs index 6ab527d8c90..aebc5138f40 100644 --- a/csharp/ql/test/query-tests/Nullness/E.cs +++ b/csharp/ql/test/query-tests/Nullness/E.cs @@ -90,12 +90,12 @@ public class E switch (switchguard) { case MY_CONST_A: - vals[0] = 0; // GOOD (false positive) + vals[0] = 0; // GOOD break; case MY_CONST_C: break; case MY_CONST_B: - vals[0] = 0; // GOOD (false positive) + vals[0] = 0; // GOOD break; default: throw new Exception(); diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index b519fefeb39..ff443d33616 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -717,8 +717,10 @@ | D.cs:76:21:76:30 | ... == ... | false | D.cs:76:21:76:22 | access to local variable o8 | non-null | | D.cs:76:21:76:30 | ... == ... | true | D.cs:75:18:75:22 | access to field maybe | true | | D.cs:76:21:76:30 | ... == ... | true | D.cs:76:21:76:22 | access to local variable o8 | null | +| D.cs:77:13:77:22 | ... == ... | true | D.cs:76:21:76:30 | ... == ... | false | | D.cs:78:13:78:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:78:13:78:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | +| D.cs:79:13:79:23 | ... != ... | false | D.cs:76:21:76:30 | ... == ... | true | | D.cs:80:13:80:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:80:13:80:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | | D.cs:82:13:82:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | @@ -1152,6 +1154,10 @@ | E.cs:85:18:85:29 | ... != ... | true | E.cs:85:18:85:21 | access to parameter vals | non-null | | E.cs:85:18:85:35 | ... && ... | true | E.cs:85:18:85:29 | ... != ... | true | | E.cs:85:18:85:35 | ... && ... | true | E.cs:85:34:85:35 | access to parameter b2 | true | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:83:13:83:24 | ... != ... | true | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:83:29:83:30 | access to parameter b1 | true | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:85:18:85:29 | ... != ... | true | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:85:34:85:35 | access to parameter b2 | true | | E.cs:107:15:107:25 | Int32[] arr2 = ... | non-null | E.cs:107:15:107:18 | access to local variable arr2 | non-null | | E.cs:107:15:107:25 | Int32[] arr2 = ... | null | E.cs:107:15:107:18 | access to local variable arr2 | null | | E.cs:109:13:109:39 | ... = ... | non-null | E.cs:109:13:109:16 | access to local variable arr2 | non-null | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index 9a58ca9330c..3af6e31daa5 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -10,7 +10,6 @@ | D.cs:32:9:32:13 | access to parameter param | Variable '$@' may be null here as suggested by $@ null check. | D.cs:26:32:26:36 | param | param | D.cs:28:13:28:25 | ... != ... | this | | D.cs:62:13:62:14 | access to local variable o5 | Variable '$@' may be null here because of $@ assignment. | D.cs:58:13:58:14 | o5 | o5 | D.cs:58:13:58:41 | String o5 = ... | this | | D.cs:73:13:73:14 | access to local variable o7 | Variable '$@' may be null here because of $@ assignment. | D.cs:68:13:68:14 | o7 | o7 | D.cs:68:13:68:34 | String o7 = ... | this | -| D.cs:78:13:78:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | | D.cs:80:13:80:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | | D.cs:82:13:82:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | | D.cs:84:13:84:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | @@ -55,10 +54,6 @@ | E.cs:43:13:43:16 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:37:9:37:19 | ... = ... | this | | E.cs:61:13:61:17 | access to local variable slice | Variable '$@' may be null here because of $@ assignment. | E.cs:51:22:51:26 | slice | slice | E.cs:51:22:51:33 | List slice = ... | this | | E.cs:73:13:73:15 | access to parameter arr | Variable '$@' may be null here as suggested by $@ null check. | E.cs:66:40:66:42 | arr | arr | E.cs:70:22:70:32 | ... == ... | this | -| E.cs:93:17:93:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:83:13:83:24 | ... != ... | this | -| E.cs:93:17:93:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:85:18:85:29 | ... != ... | this | -| E.cs:98:17:98:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:83:13:83:24 | ... != ... | this | -| E.cs:98:17:98:20 | access to parameter vals | Variable '$@' may be null here as suggested by $@ null check. | E.cs:80:27:80:30 | vals | vals | E.cs:85:18:85:29 | ... != ... | this | | E.cs:112:13:112:16 | access to local variable arr2 | Variable '$@' may be null here because of $@ assignment. | E.cs:107:15:107:18 | arr2 | arr2 | E.cs:107:15:107:25 | Int32[] arr2 = ... | this | | E.cs:125:33:125:35 | access to local variable obj | Variable '$@' may be null here because of $@ assignment. | E.cs:119:13:119:15 | obj | obj | E.cs:137:25:137:34 | ... = ... | this | | E.cs:159:13:159:16 | access to local variable obj2 | Variable '$@' may be null here as suggested by $@ null check. | E.cs:152:16:152:19 | obj2 | obj2 | E.cs:153:13:153:24 | ... != ... | this | From d25bd598db9ed13e2e14add02aa7d3a6034c4d7c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 30 Nov 2018 17:06:37 +0100 Subject: [PATCH 5/8] C#: Add change note --- change-notes/1.20/analysis-csharp.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.20/analysis-csharp.md b/change-notes/1.20/analysis-csharp.md index 2fb90f6cdec..3fb6740fd76 100644 --- a/change-notes/1.20/analysis-csharp.md +++ b/change-notes/1.20/analysis-csharp.md @@ -11,6 +11,8 @@ | *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* | | Off-by-one comparison against container length (cs/index-out-of-bounds) | Fewer false positives | Results have been removed when there are additional guards on the index. | +| Dereferenced variable is always null (cs/dereferenced-value-is-always-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. | +| Dereferenced variable may be null (cs/dereferenced-value-may-be-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. | ## Changes to code extraction From 4739a6334e58275f521bca6dc7e33feb3ffdf124 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 3 Dec 2018 15:33:00 +0100 Subject: [PATCH 6/8] C#: Fix a bug and generalize guards implication logic --- .../semmle/code/csharp/controlflow/Guards.qll | 44 +++-- .../semmle/code/csharp/dataflow/Nullness.qll | 7 +- .../controlflow/guards/Guards.cs | 53 ++++++ .../controlflow/guards/Implications.expected | 63 +++++++ csharp/ql/test/query-tests/Nullness/D.cs | 2 +- .../Nullness/Implications.expected | 163 ++++++++++++++++++ .../query-tests/Nullness/NullMaybe.expected | 1 - 7 files changed, 310 insertions(+), 23 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index f55e7836dfe..1a8a097f6cb 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -956,13 +956,13 @@ module Internal { */ private predicate guardImpliesNotEqual(Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) { relevantEq(def, vDef) and - exists(DereferenceableExpr de | - de = def.getARead() | + exists(AssignableRead ar | + ar = def.getARead() | // For example: // if (de == null); vGuard = TBooleanValue(false); vDef = TNullValue(true) // but not // if (de == "abc"); vGuard = TBooleanValue(false); vDef = TNullValue(false) - guard = getAnEqualityCheckVal(de, vGuard.getDualValue(), vDef) and + guard = getAnEqualityCheckVal(ar, vGuard.getDualValue(), vDef) and vDef.isSingleton() or // For example: @@ -970,13 +970,13 @@ module Internal { // or // if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false) exists(NullValue nv | - guard = de.getANullCheck(vGuard, any(boolean b | nv = TNullValue(b))) | + guard = ar.(DereferenceableExpr).getANullCheck(vGuard, any(boolean b | nv = TNullValue(b))) | vDef = nv.getDualValue() ) or // For example: - // if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false) - guard = getAnEqualityCheckVal(de, vGuard, vDef.getDualValue()) + // if (de == false); vGuard = TBooleanValue(true); vDef = TBooleanValue(true) + guard = getAnEqualityCheckVal(ar, vGuard, vDef.getDualValue()) ) } @@ -1040,7 +1040,7 @@ module Internal { * Holds if `e` has abstract value `v` and may be assigned to `def` without going * through back edges, and all other possible ultimate definitions of `def` do not * have abstract value `v`. The trivial case where `def` is an explicit update with - * source `e is excluded. + * source `e` is excluded. */ private predicate uniqueValue(PreSsa::Definition def, Expr e, AbstractValue v) { possibleValue(def, false, e, v) and @@ -1178,30 +1178,41 @@ module Internal { polarity = false ) or - exists(ConditionalExpr cond, boolean branch, BoolLiteral boolLit, boolean b | - b = boolLit.getBoolValue() and + exists(ConditionalExpr cond, boolean branch, Expr e, AbstractValue v | + e = v.getAnExpr() and ( - cond.getThen() = boolLit and branch = true + cond.getThen() = e and branch = true or - cond.getElse() = boolLit and branch = false + cond.getElse() = e and branch = false ) | g1 = cond and - v1 = TBooleanValue(b.booleanNot()) and + v1 = v.getDualValue() and ( + // g1 === g2 ? e : ...; g2 = cond.getCondition() and v2 = TBooleanValue(branch.booleanNot()) or + // g1 === ... ? g2 : e g2 = cond.getThen() and branch = false and v2 = v1 or + // g1 === g2 ? ... : e g2 = cond.getElse() and branch = true and v2 = v1 ) ) or + v1 = g1.getAValue() and + v1 = any(MatchValue mv | + mv.isMatch() and + g2 = g1 and + v2.getAnExpr() = mv.getCaseStmt().(ConstCase).getExpr() and + v1 != v2 + ) + or exists(boolean isNull | g1 = g2.(DereferenceableExpr).getANullCheck(v1, isNull) | v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) and @@ -1238,15 +1249,16 @@ module Internal { ) or exists(PreSsa::Definition def, AbstractValue v | - // If `def = g2 ? v : ...` or `def = g2 ? ... : v` then a guard `g1` - // proving `def != v` ensures that `g2` evaluates to `b2`. + // If for example `def = g2 ? v : ...`, then a guard `g1` proving `def != v` + // ensures that `g2` evaluates to `false`. conditionalAssignVal(g2, v2.getDualValue(), def, v) and guardImpliesNotEqual(g1, v1, def, v) ) or exists(PreSsa::Definition def, Expr e, AbstractValue v | - // If `def = g2 ? v : ...` and all other assignments to `def` are different from - // `v` then a guard proving `def == v` ensures that `g2` evaluates to `v2`. + // If for example `def = g2 ? v : ...` and all other assignments to `def` are + // different from `v`, then a guard proving `def == v` ensures that `g2` + // evaluates to `true`. uniqueValue(def, e, v) and guardImpliesEqual(g1, v1, def, v) and g2.preControlsDirect(any(PreBasicBlocks::PreBasicBlock bb | e = bb.getAnElement()), v2) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll index 7cbf21232da..5f0f7932b90 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll @@ -190,7 +190,8 @@ private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason) /** * Holds if `def1` being `null` in basic block `bb1` implies that `def2` might - * be null in basic block `bb2`. The SSA definitions share the same source variable. + * be `null` in basic block `bb2`. The SSA definitions share the same source + * variable. */ private predicate defNullImpliesStep(Ssa::Definition def1, BasicBlock bb1, Ssa::Definition def2, BasicBlock bb2) { exists(Ssa::SourceVariable v | @@ -374,10 +375,6 @@ class Dereference extends G::DereferenceableExpr { defReaches(v.getAnSsaDefinition(), this, true) } - /** - * Holds if assignable access `aa` is the first dereference of an assignable - * in a block, where it is suspected of being `null`. - */ pragma[noinline] private predicate nullDerefCandidate(Ssa::Definition origin) { exists(Ssa::Definition ssa, BasicBlock bb | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs index 8eeff60e992..75c83ac9b89 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs @@ -209,4 +209,57 @@ public class Guards } } } + + void M18(bool b1) + { + var b2 = true; + if (b1) + b2 = false; + switch (b2) + { + case true : + return; + return; + } + } + + void M19(bool b1) + { + var b2 = false; + if (b1) + b2 = true; + switch (b2) + { + case true : + return; + return; + } + } + + void M20(bool b) + { + var i = 0; + if (b) + i = 1; + switch (i) + { + case 1 : + return; + return; + } + } + + enum E { A, B, C } + void M21(bool b) + { + var e = E.A; + if (b) + e = E.B; + switch (e) + { + case E.B : + return; + return; + } + } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 7c68d807a82..7e78c7d7198 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -1,5 +1,9 @@ | Assert.cs:9:16:9:32 | String s = ... | non-null | Assert.cs:9:16:9:16 | access to local variable s | non-null | | Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null | +| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:20:9:20 | access to parameter b | false | +| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:31:9:32 | "" | non-null | +| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:20:9:20 | access to parameter b | true | +| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:24:9:27 | null | null | | Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | | Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:9:20:9:20 | access to parameter b | true | @@ -10,18 +14,30 @@ | Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | | Assert.cs:16:16:16:32 | String s = ... | non-null | Assert.cs:16:16:16:16 | access to local variable s | non-null | | Assert.cs:16:16:16:32 | String s = ... | null | Assert.cs:16:16:16:16 | access to local variable s | null | +| Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | Assert.cs:16:20:16:20 | access to parameter b | false | +| Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | Assert.cs:16:31:16:32 | "" | non-null | +| Assert.cs:16:20:16:32 | ... ? ... : ... | null | Assert.cs:16:20:16:20 | access to parameter b | true | +| Assert.cs:16:20:16:32 | ... ? ... : ... | null | Assert.cs:16:24:16:27 | null | null | | Assert.cs:17:23:17:23 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | | Assert.cs:17:23:17:23 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | | Assert.cs:18:27:18:27 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | | Assert.cs:18:27:18:27 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | | Assert.cs:23:16:23:32 | String s = ... | non-null | Assert.cs:23:16:23:16 | access to local variable s | non-null | | Assert.cs:23:16:23:32 | String s = ... | null | Assert.cs:23:16:23:16 | access to local variable s | null | +| Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | Assert.cs:23:20:23:20 | access to parameter b | false | +| Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | Assert.cs:23:31:23:32 | "" | non-null | +| Assert.cs:23:20:23:32 | ... ? ... : ... | null | Assert.cs:23:20:23:20 | access to parameter b | true | +| Assert.cs:23:20:23:32 | ... ? ... : ... | null | Assert.cs:23:24:23:27 | null | null | | Assert.cs:24:26:24:26 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | | Assert.cs:24:26:24:26 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | | Assert.cs:25:27:25:27 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | | Assert.cs:25:27:25:27 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | | Assert.cs:30:16:30:32 | String s = ... | non-null | Assert.cs:30:16:30:16 | access to local variable s | non-null | | Assert.cs:30:16:30:32 | String s = ... | null | Assert.cs:30:16:30:16 | access to local variable s | null | +| Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | Assert.cs:30:20:30:20 | access to parameter b | false | +| Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | Assert.cs:30:31:30:32 | "" | non-null | +| Assert.cs:30:20:30:32 | ... ? ... : ... | null | Assert.cs:30:20:30:20 | access to parameter b | true | +| Assert.cs:30:20:30:32 | ... ? ... : ... | null | Assert.cs:30:24:30:27 | null | null | | Assert.cs:31:23:31:23 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | | Assert.cs:31:23:31:23 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | | Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:30:20:30:20 | access to parameter b | false | @@ -32,6 +48,10 @@ | Assert.cs:32:27:32:27 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | | Assert.cs:37:16:37:32 | String s = ... | non-null | Assert.cs:37:16:37:16 | access to local variable s | non-null | | Assert.cs:37:16:37:32 | String s = ... | null | Assert.cs:37:16:37:16 | access to local variable s | null | +| Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | Assert.cs:37:20:37:20 | access to parameter b | false | +| Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | Assert.cs:37:31:37:32 | "" | non-null | +| Assert.cs:37:20:37:32 | ... ? ... : ... | null | Assert.cs:37:20:37:20 | access to parameter b | true | +| Assert.cs:37:20:37:32 | ... ? ... : ... | null | Assert.cs:37:24:37:27 | null | null | | Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | | Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | | Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:37:20:37:20 | access to parameter b | true | @@ -42,6 +62,10 @@ | Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | | Assert.cs:44:16:44:32 | String s = ... | non-null | Assert.cs:44:16:44:16 | access to local variable s | non-null | | Assert.cs:44:16:44:32 | String s = ... | null | Assert.cs:44:16:44:16 | access to local variable s | null | +| Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | Assert.cs:44:20:44:20 | access to parameter b | false | +| Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | Assert.cs:44:31:44:32 | "" | non-null | +| Assert.cs:44:20:44:32 | ... ? ... : ... | null | Assert.cs:44:20:44:20 | access to parameter b | true | +| Assert.cs:44:20:44:32 | ... ? ... : ... | null | Assert.cs:44:24:44:27 | null | null | | Assert.cs:45:24:45:24 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | | Assert.cs:45:24:45:24 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | | Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:44:20:44:20 | access to parameter b | true | @@ -52,6 +76,10 @@ | Assert.cs:46:27:46:27 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | | Assert.cs:51:16:51:32 | String s = ... | non-null | Assert.cs:51:16:51:16 | access to local variable s | non-null | | Assert.cs:51:16:51:32 | String s = ... | null | Assert.cs:51:16:51:16 | access to local variable s | null | +| Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | Assert.cs:51:20:51:20 | access to parameter b | false | +| Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | Assert.cs:51:31:51:32 | "" | non-null | +| Assert.cs:51:20:51:32 | ... ? ... : ... | null | Assert.cs:51:20:51:20 | access to parameter b | true | +| Assert.cs:51:20:51:32 | ... ? ... : ... | null | Assert.cs:51:24:51:27 | null | null | | Assert.cs:52:24:52:24 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | | Assert.cs:52:24:52:24 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | | Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:51:20:51:20 | access to parameter b | false | @@ -62,6 +90,10 @@ | Assert.cs:53:27:53:27 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | | Assert.cs:58:16:58:32 | String s = ... | non-null | Assert.cs:58:16:58:16 | access to local variable s | non-null | | Assert.cs:58:16:58:32 | String s = ... | null | Assert.cs:58:16:58:16 | access to local variable s | null | +| Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | Assert.cs:58:20:58:20 | access to parameter b | false | +| Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | Assert.cs:58:31:58:32 | "" | non-null | +| Assert.cs:58:20:58:32 | ... ? ... : ... | null | Assert.cs:58:20:58:20 | access to parameter b | true | +| Assert.cs:58:20:58:32 | ... ? ... : ... | null | Assert.cs:58:24:58:27 | null | null | | Assert.cs:59:23:59:23 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | | Assert.cs:59:23:59:23 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null | | Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:58:20:58:20 | access to parameter b | true | @@ -74,6 +106,10 @@ | Assert.cs:60:27:60:27 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null | | Assert.cs:65:16:65:32 | String s = ... | non-null | Assert.cs:65:16:65:16 | access to local variable s | non-null | | Assert.cs:65:16:65:32 | String s = ... | null | Assert.cs:65:16:65:16 | access to local variable s | null | +| Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | Assert.cs:65:20:65:20 | access to parameter b | false | +| Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | Assert.cs:65:31:65:32 | "" | non-null | +| Assert.cs:65:20:65:32 | ... ? ... : ... | null | Assert.cs:65:20:65:20 | access to parameter b | true | +| Assert.cs:65:20:65:32 | ... ? ... : ... | null | Assert.cs:65:24:65:27 | null | null | | Assert.cs:66:24:66:24 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | | Assert.cs:66:24:66:24 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null | | Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:65:20:65:20 | access to parameter b | false | @@ -86,6 +122,10 @@ | Assert.cs:67:27:67:27 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null | | Assert.cs:72:16:72:32 | String s = ... | non-null | Assert.cs:72:16:72:16 | access to local variable s | non-null | | Assert.cs:72:16:72:32 | String s = ... | null | Assert.cs:72:16:72:16 | access to local variable s | null | +| Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | Assert.cs:72:20:72:20 | access to parameter b | false | +| Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | Assert.cs:72:31:72:32 | "" | non-null | +| Assert.cs:72:20:72:32 | ... ? ... : ... | null | Assert.cs:72:20:72:20 | access to parameter b | true | +| Assert.cs:72:20:72:32 | ... ? ... : ... | null | Assert.cs:72:24:72:27 | null | null | | Assert.cs:73:23:73:23 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | | Assert.cs:73:23:73:23 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null | | Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:72:20:72:20 | access to parameter b | false | @@ -98,6 +138,10 @@ | Assert.cs:74:27:74:27 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null | | Assert.cs:79:16:79:32 | String s = ... | non-null | Assert.cs:79:16:79:16 | access to local variable s | non-null | | Assert.cs:79:16:79:32 | String s = ... | null | Assert.cs:79:16:79:16 | access to local variable s | null | +| Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | Assert.cs:79:20:79:20 | access to parameter b | false | +| Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | Assert.cs:79:31:79:32 | "" | non-null | +| Assert.cs:79:20:79:32 | ... ? ... : ... | null | Assert.cs:79:20:79:20 | access to parameter b | true | +| Assert.cs:79:20:79:32 | ... ? ... : ... | null | Assert.cs:79:24:79:27 | null | null | | Assert.cs:80:24:80:24 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | | Assert.cs:80:24:80:24 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null | | Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:79:20:79:20 | access to parameter b | true | @@ -274,6 +318,25 @@ | Guards.cs:197:13:197:29 | !... | true | Guards.cs:197:14:197:29 | call to method NullTestWrong | false | | Guards.cs:203:13:203:21 | ... != ... | false | Guards.cs:203:13:203:13 | access to parameter o | null | | Guards.cs:203:13:203:21 | ... != ... | true | Guards.cs:203:13:203:13 | access to parameter o | non-null | +| Guards.cs:215:13:215:21 | Boolean b2 = ... | false | Guards.cs:215:13:215:14 | access to local variable b2 | false | +| Guards.cs:215:13:215:21 | Boolean b2 = ... | true | Guards.cs:215:13:215:14 | access to local variable b2 | true | +| Guards.cs:217:13:217:22 | ... = ... | false | Guards.cs:217:13:217:14 | access to local variable b2 | false | +| Guards.cs:217:13:217:22 | ... = ... | true | Guards.cs:217:13:217:14 | access to local variable b2 | true | +| Guards.cs:218:17:218:18 | access to local variable b2 | match case ...: | Guards.cs:216:13:216:14 | access to parameter b1 | false | +| Guards.cs:218:17:218:18 | access to local variable b2 | match case ...: | Guards.cs:218:17:218:18 | access to local variable b2 | true | +| Guards.cs:228:13:228:22 | Boolean b2 = ... | false | Guards.cs:228:13:228:14 | access to local variable b2 | false | +| Guards.cs:228:13:228:22 | Boolean b2 = ... | true | Guards.cs:228:13:228:14 | access to local variable b2 | true | +| Guards.cs:230:13:230:21 | ... = ... | false | Guards.cs:230:13:230:14 | access to local variable b2 | false | +| Guards.cs:230:13:230:21 | ... = ... | true | Guards.cs:230:13:230:14 | access to local variable b2 | true | +| Guards.cs:231:17:231:18 | access to local variable b2 | match case ...: | Guards.cs:229:13:229:14 | access to parameter b1 | true | +| Guards.cs:231:17:231:18 | access to local variable b2 | match case ...: | Guards.cs:231:17:231:18 | access to local variable b2 | true | +| Guards.cs:231:17:231:18 | access to local variable b2 | non-match case ...: | Guards.cs:229:13:229:14 | access to parameter b1 | false | +| Guards.cs:244:17:244:17 | access to local variable i | match case ...: | Guards.cs:242:13:242:13 | access to parameter b | true | +| Guards.cs:244:17:244:17 | access to local variable i | match case ...: | Guards.cs:244:17:244:17 | access to local variable i | 1 | +| Guards.cs:244:17:244:17 | access to local variable i | non-match case ...: | Guards.cs:242:13:242:13 | access to parameter b | false | +| Guards.cs:258:17:258:17 | access to local variable e | match case ...: | Guards.cs:256:13:256:13 | access to parameter b | true | +| Guards.cs:258:17:258:17 | access to local variable e | match case ...: | Guards.cs:258:17:258:17 | access to local variable e | 1 | +| Guards.cs:258:17:258:17 | access to local variable e | non-match case ...: | Guards.cs:256:13:256:13 | access to parameter b | false | | Splitting.cs:12:17:12:25 | ... != ... | false | Splitting.cs:12:17:12:17 | access to parameter o | null | | Splitting.cs:12:17:12:25 | ... != ... | true | Splitting.cs:12:17:12:17 | access to parameter o | non-null | | Splitting.cs:22:17:22:25 | ... != ... | false | Splitting.cs:22:17:22:17 | access to parameter o | null | diff --git a/csharp/ql/test/query-tests/Nullness/D.cs b/csharp/ql/test/query-tests/Nullness/D.cs index bc2aab77cac..40419b7f577 100644 --- a/csharp/ql/test/query-tests/Nullness/D.cs +++ b/csharp/ql/test/query-tests/Nullness/D.cs @@ -77,7 +77,7 @@ public class D if (track == 2) o8.ToString(); // GOOD if (track != 42) - o8.ToString(); // GOOD (false positive) + o8.ToString(); // GOOD if (track < 42) o8.ToString(); // GOOD (false positive) if (track <= 41) diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index ff443d33616..84bbd1cb49c 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -78,6 +78,10 @@ | A.cs:78:9:78:16 | ... = ... | null | A.cs:78:15:78:16 | (...) ... | null | | Assert.cs:9:16:9:32 | String s = ... | non-null | Assert.cs:9:16:9:16 | access to local variable s | non-null | | Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null | +| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:20:9:20 | access to parameter b | false | +| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:31:9:32 | "" | non-null | +| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:20:9:20 | access to parameter b | true | +| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:24:9:27 | null | null | | Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | | Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | | Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:9:20:9:20 | access to parameter b | true | @@ -90,6 +94,10 @@ | Assert.cs:13:9:13:25 | ... = ... | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | | Assert.cs:13:9:13:25 | ... = ... | null | Assert.cs:13:9:13:9 | access to local variable s | null | | Assert.cs:13:9:13:25 | ... = ... | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | +| Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | Assert.cs:13:13:13:13 | access to parameter b | false | +| Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | Assert.cs:13:24:13:25 | "" | non-null | +| Assert.cs:13:13:13:25 | ... ? ... : ... | null | Assert.cs:13:13:13:13 | access to parameter b | true | +| Assert.cs:13:13:13:25 | ... ? ... : ... | null | Assert.cs:13:17:13:20 | null | null | | Assert.cs:14:23:14:23 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | | Assert.cs:14:23:14:23 | access to local variable s | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | | Assert.cs:15:27:15:27 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | @@ -98,6 +106,10 @@ | Assert.cs:17:9:17:25 | ... = ... | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | | Assert.cs:17:9:17:25 | ... = ... | null | Assert.cs:17:9:17:9 | access to local variable s | null | | Assert.cs:17:9:17:25 | ... = ... | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | +| Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | Assert.cs:17:13:17:13 | access to parameter b | false | +| Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | Assert.cs:17:24:17:25 | "" | non-null | +| Assert.cs:17:13:17:25 | ... ? ... : ... | null | Assert.cs:17:13:17:13 | access to parameter b | true | +| Assert.cs:17:13:17:25 | ... ? ... : ... | null | Assert.cs:17:17:17:20 | null | null | | Assert.cs:18:26:18:26 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | | Assert.cs:18:26:18:26 | access to local variable s | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | | Assert.cs:19:27:19:27 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | @@ -106,6 +118,10 @@ | Assert.cs:21:9:21:25 | ... = ... | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | | Assert.cs:21:9:21:25 | ... = ... | null | Assert.cs:21:9:21:9 | access to local variable s | null | | Assert.cs:21:9:21:25 | ... = ... | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | +| Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | Assert.cs:21:13:21:13 | access to parameter b | false | +| Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | Assert.cs:21:24:21:25 | "" | non-null | +| Assert.cs:21:13:21:25 | ... ? ... : ... | null | Assert.cs:21:13:21:13 | access to parameter b | true | +| Assert.cs:21:13:21:25 | ... ? ... : ... | null | Assert.cs:21:17:21:20 | null | null | | Assert.cs:22:23:22:23 | access to local variable s | non-null | Assert.cs:21:13:21:25 | ... ? ... : ... | non-null | | Assert.cs:22:23:22:23 | access to local variable s | null | Assert.cs:21:13:21:25 | ... ? ... : ... | null | | Assert.cs:22:23:22:31 | ... == ... | false | Assert.cs:21:13:21:13 | access to parameter b | false | @@ -118,6 +134,10 @@ | Assert.cs:25:9:25:25 | ... = ... | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | | Assert.cs:25:9:25:25 | ... = ... | null | Assert.cs:25:9:25:9 | access to local variable s | null | | Assert.cs:25:9:25:25 | ... = ... | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | +| Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | Assert.cs:25:13:25:13 | access to parameter b | false | +| Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | Assert.cs:25:24:25:25 | "" | non-null | +| Assert.cs:25:13:25:25 | ... ? ... : ... | null | Assert.cs:25:13:25:13 | access to parameter b | true | +| Assert.cs:25:13:25:25 | ... ? ... : ... | null | Assert.cs:25:17:25:20 | null | null | | Assert.cs:26:23:26:23 | access to local variable s | non-null | Assert.cs:25:13:25:25 | ... ? ... : ... | non-null | | Assert.cs:26:23:26:23 | access to local variable s | null | Assert.cs:25:13:25:25 | ... ? ... : ... | null | | Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:25:13:25:13 | access to parameter b | true | @@ -130,6 +150,10 @@ | Assert.cs:29:9:29:25 | ... = ... | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | | Assert.cs:29:9:29:25 | ... = ... | null | Assert.cs:29:9:29:9 | access to local variable s | null | | Assert.cs:29:9:29:25 | ... = ... | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | +| Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | Assert.cs:29:13:29:13 | access to parameter b | false | +| Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | Assert.cs:29:24:29:25 | "" | non-null | +| Assert.cs:29:13:29:25 | ... ? ... : ... | null | Assert.cs:29:13:29:13 | access to parameter b | true | +| Assert.cs:29:13:29:25 | ... ? ... : ... | null | Assert.cs:29:17:29:20 | null | null | | Assert.cs:30:24:30:24 | access to local variable s | non-null | Assert.cs:29:13:29:25 | ... ? ... : ... | non-null | | Assert.cs:30:24:30:24 | access to local variable s | null | Assert.cs:29:13:29:25 | ... ? ... : ... | null | | Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:29:13:29:13 | access to parameter b | true | @@ -142,6 +166,10 @@ | Assert.cs:33:9:33:25 | ... = ... | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | | Assert.cs:33:9:33:25 | ... = ... | null | Assert.cs:33:9:33:9 | access to local variable s | null | | Assert.cs:33:9:33:25 | ... = ... | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | +| Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | Assert.cs:33:13:33:13 | access to parameter b | false | +| Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | Assert.cs:33:24:33:25 | "" | non-null | +| Assert.cs:33:13:33:25 | ... ? ... : ... | null | Assert.cs:33:13:33:13 | access to parameter b | true | +| Assert.cs:33:13:33:25 | ... ? ... : ... | null | Assert.cs:33:17:33:20 | null | null | | Assert.cs:34:24:34:24 | access to local variable s | non-null | Assert.cs:33:13:33:25 | ... ? ... : ... | non-null | | Assert.cs:34:24:34:24 | access to local variable s | null | Assert.cs:33:13:33:25 | ... ? ... : ... | null | | Assert.cs:34:24:34:32 | ... == ... | false | Assert.cs:33:13:33:13 | access to parameter b | false | @@ -154,6 +182,10 @@ | Assert.cs:37:9:37:25 | ... = ... | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | | Assert.cs:37:9:37:25 | ... = ... | null | Assert.cs:37:9:37:9 | access to local variable s | null | | Assert.cs:37:9:37:25 | ... = ... | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | +| Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | Assert.cs:37:13:37:13 | access to parameter b | false | +| Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | Assert.cs:37:24:37:25 | "" | non-null | +| Assert.cs:37:13:37:25 | ... ? ... : ... | null | Assert.cs:37:13:37:13 | access to parameter b | true | +| Assert.cs:37:13:37:25 | ... ? ... : ... | null | Assert.cs:37:17:37:20 | null | null | | Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:13:37:25 | ... ? ... : ... | non-null | | Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:13:37:25 | ... ? ... : ... | null | | Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:37:13:37:13 | access to parameter b | true | @@ -168,6 +200,10 @@ | Assert.cs:41:9:41:25 | ... = ... | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | | Assert.cs:41:9:41:25 | ... = ... | null | Assert.cs:41:9:41:9 | access to local variable s | null | | Assert.cs:41:9:41:25 | ... = ... | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | +| Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | Assert.cs:41:13:41:13 | access to parameter b | false | +| Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | Assert.cs:41:24:41:25 | "" | non-null | +| Assert.cs:41:13:41:25 | ... ? ... : ... | null | Assert.cs:41:13:41:13 | access to parameter b | true | +| Assert.cs:41:13:41:25 | ... ? ... : ... | null | Assert.cs:41:17:41:20 | null | null | | Assert.cs:42:24:42:24 | access to local variable s | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | | Assert.cs:42:24:42:24 | access to local variable s | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | | Assert.cs:42:24:42:32 | ... == ... | false | Assert.cs:41:13:41:13 | access to parameter b | false | @@ -182,6 +218,10 @@ | Assert.cs:45:9:45:25 | ... = ... | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | | Assert.cs:45:9:45:25 | ... = ... | null | Assert.cs:45:9:45:9 | access to local variable s | null | | Assert.cs:45:9:45:25 | ... = ... | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | +| Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | Assert.cs:45:13:45:13 | access to parameter b | false | +| Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | Assert.cs:45:24:45:25 | "" | non-null | +| Assert.cs:45:13:45:25 | ... ? ... : ... | null | Assert.cs:45:13:45:13 | access to parameter b | true | +| Assert.cs:45:13:45:25 | ... ? ... : ... | null | Assert.cs:45:17:45:20 | null | null | | Assert.cs:46:23:46:23 | access to local variable s | non-null | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | | Assert.cs:46:23:46:23 | access to local variable s | null | Assert.cs:45:13:45:25 | ... ? ... : ... | null | | Assert.cs:46:23:46:31 | ... == ... | false | Assert.cs:45:13:45:13 | access to parameter b | false | @@ -196,6 +236,10 @@ | Assert.cs:49:9:49:25 | ... = ... | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | | Assert.cs:49:9:49:25 | ... = ... | null | Assert.cs:49:9:49:9 | access to local variable s | null | | Assert.cs:49:9:49:25 | ... = ... | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | +| Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | Assert.cs:49:13:49:13 | access to parameter b | false | +| Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | Assert.cs:49:24:49:25 | "" | non-null | +| Assert.cs:49:13:49:25 | ... ? ... : ... | null | Assert.cs:49:13:49:13 | access to parameter b | true | +| Assert.cs:49:13:49:25 | ... ? ... : ... | null | Assert.cs:49:17:49:20 | null | null | | Assert.cs:50:24:50:24 | access to local variable s | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | | Assert.cs:50:24:50:24 | access to local variable s | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | | Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:49:13:49:13 | access to parameter b | true | @@ -292,6 +336,10 @@ | C.cs:34:13:34:21 | ... == ... | true | C.cs:34:13:34:13 | access to parameter o | null | | C.cs:40:13:40:35 | String s = ... | non-null | C.cs:40:13:40:13 | access to local variable s | non-null | | C.cs:40:13:40:35 | String s = ... | null | C.cs:40:13:40:13 | access to local variable s | null | +| C.cs:40:17:40:35 | ... ? ... : ... | non-null | C.cs:40:17:40:23 | call to method Maybe | false | +| C.cs:40:17:40:35 | ... ? ... : ... | non-null | C.cs:40:34:40:35 | "" | non-null | +| C.cs:40:17:40:35 | ... ? ... : ... | null | C.cs:40:17:40:23 | call to method Maybe | true | +| C.cs:40:17:40:35 | ... ? ... : ... | null | C.cs:40:27:40:30 | null | null | | C.cs:41:22:41:22 | access to local variable s | non-null | C.cs:40:17:40:35 | ... ? ... : ... | non-null | | C.cs:41:22:41:22 | access to local variable s | null | C.cs:40:17:40:35 | ... ? ... : ... | null | | C.cs:41:22:41:30 | ... == ... | false | C.cs:40:17:40:23 | call to method Maybe | false | @@ -304,6 +352,10 @@ | C.cs:44:9:44:31 | ... = ... | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | | C.cs:44:9:44:31 | ... = ... | null | C.cs:44:9:44:9 | access to local variable s | null | | C.cs:44:9:44:31 | ... = ... | null | C.cs:44:13:44:31 | ... ? ... : ... | null | +| C.cs:44:13:44:31 | ... ? ... : ... | non-null | C.cs:44:13:44:19 | call to method Maybe | false | +| C.cs:44:13:44:31 | ... ? ... : ... | non-null | C.cs:44:30:44:31 | "" | non-null | +| C.cs:44:13:44:31 | ... ? ... : ... | null | C.cs:44:13:44:19 | call to method Maybe | true | +| C.cs:44:13:44:31 | ... ? ... : ... | null | C.cs:44:23:44:26 | null | null | | C.cs:45:22:45:22 | access to local variable s | non-null | C.cs:44:13:44:31 | ... ? ... : ... | non-null | | C.cs:45:22:45:22 | access to local variable s | null | C.cs:44:13:44:31 | ... ? ... : ... | null | | C.cs:45:22:45:30 | ... != ... | false | C.cs:44:13:44:19 | call to method Maybe | true | @@ -320,24 +372,40 @@ | C.cs:53:9:53:10 | access to local variable o1 | null | C.cs:51:18:51:29 | object creation of type Object | null | | C.cs:55:13:55:36 | String o2 = ... | non-null | C.cs:55:13:55:14 | access to local variable o2 | non-null | | C.cs:55:13:55:36 | String o2 = ... | null | C.cs:55:13:55:14 | access to local variable o2 | null | +| C.cs:55:18:55:36 | ... ? ... : ... | non-null | C.cs:55:18:55:24 | call to method Maybe | false | +| C.cs:55:18:55:36 | ... ? ... : ... | non-null | C.cs:55:35:55:36 | "" | non-null | +| C.cs:55:18:55:36 | ... ? ... : ... | null | C.cs:55:18:55:24 | call to method Maybe | true | +| C.cs:55:18:55:36 | ... ? ... : ... | null | C.cs:55:28:55:31 | null | null | | C.cs:56:23:56:24 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | | C.cs:56:23:56:24 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | | C.cs:57:9:57:10 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | | C.cs:57:9:57:10 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | | C.cs:62:13:62:46 | Object o1 = ... | non-null | C.cs:62:13:62:14 | access to local variable o1 | non-null | | C.cs:62:13:62:46 | Object o1 = ... | null | C.cs:62:13:62:14 | access to local variable o1 | null | +| C.cs:62:18:62:46 | ... ? ... : ... | non-null | C.cs:62:18:62:24 | call to method Maybe | false | +| C.cs:62:18:62:46 | ... ? ... : ... | non-null | C.cs:62:35:62:46 | object creation of type Object | non-null | +| C.cs:62:18:62:46 | ... ? ... : ... | null | C.cs:62:18:62:24 | call to method Maybe | true | +| C.cs:62:18:62:46 | ... ? ... : ... | null | C.cs:62:28:62:31 | null | null | | C.cs:63:23:63:24 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | | C.cs:63:23:63:24 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | | C.cs:64:9:64:10 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | | C.cs:64:9:64:10 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | | C.cs:66:13:66:46 | Object o2 = ... | non-null | C.cs:66:13:66:14 | access to local variable o2 | non-null | | C.cs:66:13:66:46 | Object o2 = ... | null | C.cs:66:13:66:14 | access to local variable o2 | null | +| C.cs:66:18:66:46 | ... ? ... : ... | non-null | C.cs:66:18:66:24 | call to method Maybe | false | +| C.cs:66:18:66:46 | ... ? ... : ... | non-null | C.cs:66:35:66:46 | object creation of type Object | non-null | +| C.cs:66:18:66:46 | ... ? ... : ... | null | C.cs:66:18:66:24 | call to method Maybe | true | +| C.cs:66:18:66:46 | ... ? ... : ... | null | C.cs:66:28:66:31 | null | null | | C.cs:67:23:67:24 | access to local variable o1 | non-null | C.cs:62:18:62:46 | ... ? ... : ... | non-null | | C.cs:67:23:67:24 | access to local variable o1 | null | C.cs:62:18:62:46 | ... ? ... : ... | null | | C.cs:68:9:68:10 | access to local variable o2 | non-null | C.cs:66:18:66:46 | ... ? ... : ... | non-null | | C.cs:68:9:68:10 | access to local variable o2 | null | C.cs:66:18:66:46 | ... ? ... : ... | null | | C.cs:70:13:70:46 | Object o3 = ... | non-null | C.cs:70:13:70:14 | access to local variable o3 | non-null | | C.cs:70:13:70:46 | Object o3 = ... | null | C.cs:70:13:70:14 | access to local variable o3 | null | +| C.cs:70:18:70:46 | ... ? ... : ... | non-null | C.cs:70:18:70:24 | call to method Maybe | false | +| C.cs:70:18:70:46 | ... ? ... : ... | non-null | C.cs:70:35:70:46 | object creation of type Object | non-null | +| C.cs:70:18:70:46 | ... ? ... : ... | null | C.cs:70:18:70:24 | call to method Maybe | true | +| C.cs:70:18:70:46 | ... ? ... : ... | null | C.cs:70:28:70:31 | null | null | | C.cs:71:26:71:27 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | | C.cs:71:26:71:27 | access to local variable o3 | null | C.cs:70:18:70:46 | ... ? ... : ... | null | | C.cs:72:9:72:10 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | @@ -367,6 +435,10 @@ | C.cs:90:13:90:13 | access to local variable o | null | C.cs:88:20:88:23 | null | null | | C.cs:95:13:95:45 | Object o = ... | non-null | C.cs:95:13:95:13 | access to local variable o | non-null | | C.cs:95:13:95:45 | Object o = ... | null | C.cs:95:13:95:13 | access to local variable o | null | +| C.cs:95:17:95:45 | ... ? ... : ... | non-null | C.cs:95:17:95:23 | call to method Maybe | false | +| C.cs:95:17:95:45 | ... ? ... : ... | non-null | C.cs:95:34:95:45 | object creation of type Object | non-null | +| C.cs:95:17:95:45 | ... ? ... : ... | null | C.cs:95:17:95:23 | call to method Maybe | true | +| C.cs:95:17:95:45 | ... ? ... : ... | null | C.cs:95:27:95:30 | null | null | | C.cs:96:15:96:15 | access to local variable o | non-null | C.cs:95:17:95:45 | ... ? ... : ... | non-null | | C.cs:96:15:96:15 | access to local variable o | null | C.cs:95:17:95:45 | ... ? ... : ... | null | | C.cs:97:13:97:13 | access to local variable o | non-null | C.cs:95:17:95:45 | ... ? ... : ... | non-null | @@ -385,6 +457,8 @@ | C.cs:114:22:114:36 | ... == ... | true | C.cs:114:22:114:28 | access to local variable colours | null | | C.cs:114:22:114:59 | ... \|\| ... | false | C.cs:114:22:114:36 | ... == ... | false | | C.cs:114:22:114:59 | ... \|\| ... | false | C.cs:114:41:114:59 | ... == ... | false | +| C.cs:114:22:114:90 | ... ? ... : ... | null | C.cs:114:22:114:59 | ... \|\| ... | false | +| C.cs:114:22:114:90 | ... ? ... : ... | null | C.cs:114:73:114:90 | call to method ToString | null | | C.cs:114:41:114:47 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | | C.cs:114:41:114:47 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | | C.cs:114:73:114:79 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | @@ -511,6 +585,10 @@ | C.cs:205:13:205:20 | ... = ... | null | C.cs:205:17:205:20 | null | null | | C.cs:211:13:211:35 | String s = ... | non-null | C.cs:211:13:211:13 | access to local variable s | non-null | | C.cs:211:13:211:35 | String s = ... | null | C.cs:211:13:211:13 | access to local variable s | null | +| C.cs:211:17:211:35 | ... ? ... : ... | non-null | C.cs:211:17:211:23 | call to method Maybe | false | +| C.cs:211:17:211:35 | ... ? ... : ... | non-null | C.cs:211:34:211:35 | "" | non-null | +| C.cs:211:17:211:35 | ... ? ... : ... | null | C.cs:211:17:211:23 | call to method Maybe | true | +| C.cs:211:17:211:35 | ... ? ... : ... | null | C.cs:211:27:211:30 | null | null | | C.cs:212:13:212:13 | access to local variable s | non-null | C.cs:211:17:211:35 | ... ? ... : ... | non-null | | C.cs:212:13:212:13 | access to local variable s | null | C.cs:211:17:211:35 | ... ? ... : ... | null | | C.cs:212:13:212:21 | ... != ... | false | C.cs:211:17:211:23 | call to method Maybe | true | @@ -613,6 +691,10 @@ | D.cs:39:16:39:24 | ... == ... | true | D.cs:39:16:39:16 | access to parameter x | null | | D.cs:44:13:44:44 | Object o1 = ... | non-null | D.cs:44:13:44:14 | access to local variable o1 | non-null | | D.cs:44:13:44:44 | Object o1 = ... | null | D.cs:44:13:44:14 | access to local variable o1 | null | +| D.cs:44:18:44:44 | ... ? ... : ... | non-null | D.cs:44:18:44:22 | access to field maybe | false | +| D.cs:44:18:44:44 | ... ? ... : ... | non-null | D.cs:44:33:44:44 | object creation of type Object | non-null | +| D.cs:44:18:44:44 | ... ? ... : ... | null | D.cs:44:18:44:22 | access to field maybe | true | +| D.cs:44:18:44:44 | ... ? ... : ... | null | D.cs:44:26:44:29 | null | null | | D.cs:45:13:45:14 | access to local variable o1 | non-null | D.cs:44:18:44:44 | ... ? ... : ... | non-null | | D.cs:45:13:45:14 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | | D.cs:45:13:45:22 | ... != ... | false | D.cs:44:18:44:22 | access to field maybe | true | @@ -623,6 +705,10 @@ | D.cs:45:25:45:26 | access to local variable o1 | null | D.cs:44:18:44:44 | ... ? ... : ... | null | | D.cs:47:13:47:34 | String o2 = ... | non-null | D.cs:47:13:47:14 | access to local variable o2 | non-null | | D.cs:47:13:47:34 | String o2 = ... | null | D.cs:47:13:47:14 | access to local variable o2 | null | +| D.cs:47:18:47:34 | ... ? ... : ... | non-null | D.cs:47:18:47:22 | access to field maybe | false | +| D.cs:47:18:47:34 | ... ? ... : ... | non-null | D.cs:47:33:47:34 | "" | non-null | +| D.cs:47:18:47:34 | ... ? ... : ... | null | D.cs:47:18:47:22 | access to field maybe | true | +| D.cs:47:18:47:34 | ... ? ... : ... | null | D.cs:47:26:47:29 | null | null | | D.cs:48:13:48:14 | access to local variable o2 | non-null | D.cs:47:18:47:34 | ... ? ... : ... | non-null | | D.cs:48:13:48:14 | access to local variable o2 | null | D.cs:47:18:47:34 | ... ? ... : ... | null | | D.cs:48:13:48:24 | ... is ... | false | D.cs:47:18:47:22 | access to field maybe | true | @@ -639,10 +725,18 @@ | D.cs:51:14:51:35 | ... = ... | non-null | D.cs:51:19:51:35 | ... ? ... : ... | non-null | | D.cs:51:14:51:35 | ... = ... | null | D.cs:51:14:51:15 | access to local variable o3 | null | | D.cs:51:14:51:35 | ... = ... | null | D.cs:51:19:51:35 | ... ? ... : ... | null | +| D.cs:51:19:51:35 | ... ? ... : ... | non-null | D.cs:51:19:51:23 | access to field maybe | false | +| D.cs:51:19:51:35 | ... ? ... : ... | non-null | D.cs:51:34:51:35 | "" | non-null | +| D.cs:51:19:51:35 | ... ? ... : ... | null | D.cs:51:19:51:23 | access to field maybe | true | +| D.cs:51:19:51:35 | ... ? ... : ... | null | D.cs:51:27:51:30 | null | null | | D.cs:52:13:52:14 | access to local variable o3 | non-null | D.cs:51:19:51:35 | ... ? ... : ... | non-null | | D.cs:52:13:52:14 | access to local variable o3 | null | D.cs:51:19:51:35 | ... ? ... : ... | null | | D.cs:54:13:54:34 | String o4 = ... | non-null | D.cs:54:13:54:14 | access to local variable o4 | non-null | | D.cs:54:13:54:34 | String o4 = ... | null | D.cs:54:13:54:14 | access to local variable o4 | null | +| D.cs:54:18:54:34 | ... ? ... : ... | non-null | D.cs:54:18:54:22 | access to field maybe | false | +| D.cs:54:18:54:34 | ... ? ... : ... | non-null | D.cs:54:33:54:34 | "" | non-null | +| D.cs:54:18:54:34 | ... ? ... : ... | null | D.cs:54:18:54:22 | access to field maybe | true | +| D.cs:54:18:54:34 | ... ? ... : ... | null | D.cs:54:26:54:29 | null | null | | D.cs:55:13:55:42 | ... != ... | false | D.cs:55:14:55:32 | ... && ... | false | | D.cs:55:13:55:42 | ... != ... | true | D.cs:55:14:55:32 | ... && ... | true | | D.cs:55:14:55:32 | ... && ... | true | D.cs:55:14:55:18 | ... > ... | true | @@ -657,6 +751,10 @@ | D.cs:56:13:56:14 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | | D.cs:58:13:58:41 | String o5 = ... | non-null | D.cs:58:13:58:14 | access to local variable o5 | non-null | | D.cs:58:13:58:41 | String o5 = ... | null | D.cs:58:13:58:14 | access to local variable o5 | null | +| D.cs:58:18:58:41 | ... ? ... : ... | non-null | D.cs:58:19:58:28 | ... != ... | true | +| D.cs:58:18:58:41 | ... ? ... : ... | non-null | D.cs:58:33:58:34 | "" | non-null | +| D.cs:58:18:58:41 | ... ? ... : ... | null | D.cs:58:19:58:28 | ... != ... | false | +| D.cs:58:18:58:41 | ... ? ... : ... | null | D.cs:58:38:58:41 | null | null | | D.cs:58:19:58:20 | access to local variable o4 | non-null | D.cs:54:18:54:34 | ... ? ... : ... | non-null | | D.cs:58:19:58:20 | access to local variable o4 | null | D.cs:54:18:54:34 | ... ? ... : ... | null | | D.cs:58:19:58:28 | ... != ... | false | D.cs:54:18:54:22 | access to field maybe | true | @@ -681,6 +779,10 @@ | D.cs:62:13:62:14 | access to local variable o5 | null | D.cs:58:18:58:41 | ... ? ... : ... | null | | D.cs:64:13:64:34 | String o6 = ... | non-null | D.cs:64:13:64:14 | access to local variable o6 | non-null | | D.cs:64:13:64:34 | String o6 = ... | null | D.cs:64:13:64:14 | access to local variable o6 | null | +| D.cs:64:18:64:34 | ... ? ... : ... | non-null | D.cs:64:18:64:22 | access to field maybe | false | +| D.cs:64:18:64:34 | ... ? ... : ... | non-null | D.cs:64:33:64:34 | "" | non-null | +| D.cs:64:18:64:34 | ... ? ... : ... | null | D.cs:64:18:64:22 | access to field maybe | true | +| D.cs:64:18:64:34 | ... ? ... : ... | null | D.cs:64:26:64:29 | null | null | | D.cs:65:13:65:29 | !... | false | D.cs:65:14:65:29 | call to method CustomIsNull | true | | D.cs:65:13:65:29 | !... | true | D.cs:65:14:65:29 | call to method CustomIsNull | false | | D.cs:65:14:65:29 | call to method CustomIsNull | false | D.cs:64:18:64:22 | access to field maybe | false | @@ -693,6 +795,10 @@ | D.cs:66:13:66:14 | access to local variable o6 | null | D.cs:64:18:64:34 | ... ? ... : ... | null | | D.cs:68:13:68:34 | String o7 = ... | non-null | D.cs:68:13:68:14 | access to local variable o7 | non-null | | D.cs:68:13:68:34 | String o7 = ... | null | D.cs:68:13:68:14 | access to local variable o7 | null | +| D.cs:68:18:68:34 | ... ? ... : ... | non-null | D.cs:68:18:68:22 | access to field maybe | false | +| D.cs:68:18:68:34 | ... ? ... : ... | non-null | D.cs:68:33:68:34 | "" | non-null | +| D.cs:68:18:68:34 | ... ? ... : ... | null | D.cs:68:18:68:22 | access to field maybe | true | +| D.cs:68:18:68:34 | ... ? ... : ... | null | D.cs:68:26:68:29 | null | null | | D.cs:69:13:69:36 | Boolean ok = ... | false | D.cs:69:13:69:14 | access to local variable ok | false | | D.cs:69:13:69:36 | Boolean ok = ... | true | D.cs:69:13:69:14 | access to local variable ok | true | | D.cs:69:18:69:19 | access to local variable o7 | non-null | D.cs:68:18:68:34 | ... ? ... : ... | non-null | @@ -711,16 +817,22 @@ | D.cs:73:13:73:14 | access to local variable o7 | null | D.cs:68:18:68:34 | ... ? ... : ... | null | | D.cs:75:13:75:34 | String o8 = ... | non-null | D.cs:75:13:75:14 | access to local variable o8 | non-null | | D.cs:75:13:75:34 | String o8 = ... | null | D.cs:75:13:75:14 | access to local variable o8 | null | +| D.cs:75:18:75:34 | ... ? ... : ... | non-null | D.cs:75:18:75:22 | access to field maybe | false | +| D.cs:75:18:75:34 | ... ? ... : ... | non-null | D.cs:75:33:75:34 | "" | non-null | +| D.cs:75:18:75:34 | ... ? ... : ... | null | D.cs:75:18:75:22 | access to field maybe | true | +| D.cs:75:18:75:34 | ... ? ... : ... | null | D.cs:75:26:75:29 | null | null | | D.cs:76:21:76:22 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:76:21:76:22 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | | D.cs:76:21:76:30 | ... == ... | false | D.cs:75:18:75:22 | access to field maybe | false | | D.cs:76:21:76:30 | ... == ... | false | D.cs:76:21:76:22 | access to local variable o8 | non-null | | D.cs:76:21:76:30 | ... == ... | true | D.cs:75:18:75:22 | access to field maybe | true | | D.cs:76:21:76:30 | ... == ... | true | D.cs:76:21:76:22 | access to local variable o8 | null | +| D.cs:77:13:77:22 | ... == ... | false | D.cs:76:21:76:30 | ... == ... | true | | D.cs:77:13:77:22 | ... == ... | true | D.cs:76:21:76:30 | ... == ... | false | | D.cs:78:13:78:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:78:13:78:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | | D.cs:79:13:79:23 | ... != ... | false | D.cs:76:21:76:30 | ... == ... | true | +| D.cs:79:13:79:23 | ... != ... | true | D.cs:76:21:76:30 | ... == ... | false | | D.cs:80:13:80:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | | D.cs:80:13:80:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | | D.cs:82:13:82:14 | access to local variable o8 | non-null | D.cs:75:18:75:34 | ... ? ... : ... | non-null | @@ -729,6 +841,10 @@ | D.cs:84:13:84:14 | access to local variable o8 | null | D.cs:75:18:75:34 | ... ? ... : ... | null | | D.cs:89:15:89:44 | Int32[] xs = ... | non-null | D.cs:89:15:89:16 | access to local variable xs | non-null | | D.cs:89:15:89:44 | Int32[] xs = ... | null | D.cs:89:15:89:16 | access to local variable xs | null | +| D.cs:89:20:89:44 | ... ? ... : ... | non-null | D.cs:89:20:89:24 | access to field maybe | false | +| D.cs:89:20:89:44 | ... ? ... : ... | non-null | D.cs:89:35:89:44 | array creation of type Int32[] | non-null | +| D.cs:89:20:89:44 | ... ? ... : ... | null | D.cs:89:20:89:24 | access to field maybe | true | +| D.cs:89:20:89:44 | ... ? ... : ... | null | D.cs:89:28:89:31 | null | null | | D.cs:91:13:91:14 | access to local variable xs | non-null | D.cs:89:20:89:44 | ... ? ... : ... | non-null | | D.cs:91:13:91:14 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | | D.cs:94:13:94:29 | ... = ... | false | D.cs:94:13:94:17 | access to field maybe | false | @@ -759,6 +875,10 @@ | D.cs:111:21:111:22 | access to local variable xs | null | D.cs:89:20:89:44 | ... ? ... : ... | null | | D.cs:117:13:117:32 | String x = ... | non-null | D.cs:117:13:117:13 | access to local variable x | non-null | | D.cs:117:13:117:32 | String x = ... | null | D.cs:117:13:117:13 | access to local variable x | null | +| D.cs:117:17:117:32 | ... ? ... : ... | non-null | D.cs:117:17:117:17 | access to parameter b | false | +| D.cs:117:17:117:32 | ... ? ... : ... | non-null | D.cs:117:28:117:32 | "abc" | non-null | +| D.cs:117:17:117:32 | ... ? ... : ... | null | D.cs:117:17:117:17 | access to parameter b | true | +| D.cs:117:17:117:32 | ... ? ... : ... | null | D.cs:117:21:117:24 | null | null | | D.cs:118:9:118:30 | ... = ... | non-null | D.cs:118:9:118:9 | access to local variable x | non-null | | D.cs:118:9:118:30 | ... = ... | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | | D.cs:118:9:118:30 | ... = ... | null | D.cs:118:9:118:9 | access to local variable x | null | @@ -769,6 +889,8 @@ | D.cs:118:13:118:21 | ... == ... | false | D.cs:118:13:118:13 | access to local variable x | non-null | | D.cs:118:13:118:21 | ... == ... | true | D.cs:117:17:117:17 | access to parameter b | true | | D.cs:118:13:118:21 | ... == ... | true | D.cs:118:13:118:13 | access to local variable x | null | +| D.cs:118:13:118:30 | ... ? ... : ... | null | D.cs:118:13:118:21 | ... == ... | false | +| D.cs:118:13:118:30 | ... ? ... : ... | null | D.cs:118:30:118:30 | access to local variable x | null | | D.cs:118:30:118:30 | access to local variable x | non-null | D.cs:117:17:117:32 | ... ? ... : ... | non-null | | D.cs:118:30:118:30 | access to local variable x | null | D.cs:117:17:117:32 | ... ? ... : ... | null | | D.cs:119:13:119:13 | access to local variable x | non-null | D.cs:118:13:118:30 | ... ? ... : ... | non-null | @@ -828,6 +950,8 @@ | D.cs:212:18:212:18 | access to local variable n | null | D.cs:211:20:211:23 | null | null | | D.cs:212:18:212:26 | ... == ... | false | D.cs:212:18:212:18 | access to local variable n | non-null | | D.cs:212:18:212:26 | ... == ... | true | D.cs:212:18:212:18 | access to local variable n | null | +| D.cs:212:18:212:45 | ... ? ... : ... | null | D.cs:212:18:212:26 | ... == ... | false | +| D.cs:212:18:212:45 | ... ? ... : ... | null | D.cs:212:45:212:45 | access to local variable n | null | | D.cs:212:45:212:45 | access to local variable n | non-null | D.cs:211:20:211:23 | null | non-null | | D.cs:212:45:212:45 | access to local variable n | null | D.cs:211:20:211:23 | null | null | | D.cs:213:9:213:10 | access to local variable o2 | non-null | D.cs:212:18:212:45 | ... ? ... : ... | non-null | @@ -875,6 +999,10 @@ | D.cs:240:9:240:16 | ... = ... | null | D.cs:240:13:240:16 | null | null | | D.cs:241:13:241:37 | String other = ... | non-null | D.cs:241:13:241:17 | access to local variable other | non-null | | D.cs:241:13:241:37 | String other = ... | null | D.cs:241:13:241:17 | access to local variable other | null | +| D.cs:241:21:241:37 | ... ? ... : ... | non-null | D.cs:241:21:241:25 | access to field maybe | false | +| D.cs:241:21:241:37 | ... ? ... : ... | non-null | D.cs:241:36:241:37 | "" | non-null | +| D.cs:241:21:241:37 | ... ? ... : ... | null | D.cs:241:21:241:25 | access to field maybe | true | +| D.cs:241:21:241:37 | ... ? ... : ... | null | D.cs:241:29:241:32 | null | null | | D.cs:242:13:242:17 | access to local variable other | non-null | D.cs:241:21:241:37 | ... ? ... : ... | non-null | | D.cs:242:13:242:17 | access to local variable other | null | D.cs:241:21:241:37 | ... ? ... : ... | null | | D.cs:242:13:242:25 | ... == ... | false | D.cs:241:21:241:25 | access to field maybe | false | @@ -893,6 +1021,10 @@ | D.cs:244:13:244:25 | ... != ... | true | D.cs:244:13:244:17 | access to local variable other | non-null | | D.cs:249:13:249:38 | String o2 = ... | non-null | D.cs:249:13:249:14 | access to local variable o2 | non-null | | D.cs:249:13:249:38 | String o2 = ... | null | D.cs:249:13:249:14 | access to local variable o2 | null | +| D.cs:249:18:249:38 | ... ? ... : ... | non-null | D.cs:249:19:249:25 | ... < ... | false | +| D.cs:249:18:249:38 | ... ? ... : ... | non-null | D.cs:249:37:249:38 | "" | non-null | +| D.cs:249:18:249:38 | ... ? ... : ... | null | D.cs:249:19:249:25 | ... < ... | true | +| D.cs:249:18:249:38 | ... ? ... : ... | null | D.cs:249:30:249:33 | null | null | | D.cs:251:13:251:19 | ... = ... | non-null | D.cs:251:13:251:14 | access to local variable o2 | non-null | | D.cs:251:13:251:19 | ... = ... | non-null | D.cs:251:18:251:19 | "" | non-null | | D.cs:251:13:251:19 | ... = ... | null | D.cs:251:13:251:14 | access to local variable o2 | null | @@ -999,6 +1131,10 @@ | D.cs:362:17:362:28 | ... = ... | null | D.cs:362:24:362:28 | "abc" | null | | D.cs:366:15:366:47 | Int32[] b = ... | non-null | D.cs:366:15:366:15 | access to local variable b | non-null | | D.cs:366:15:366:47 | Int32[] b = ... | null | D.cs:366:15:366:15 | access to local variable b | null | +| D.cs:366:19:366:47 | ... ? ... : ... | non-null | D.cs:366:19:366:23 | access to field maybe | false | +| D.cs:366:19:366:47 | ... ? ... : ... | non-null | D.cs:366:34:366:47 | array creation of type Int32[] | non-null | +| D.cs:366:19:366:47 | ... ? ... : ... | null | D.cs:366:19:366:23 | access to field maybe | true | +| D.cs:366:19:366:47 | ... ? ... : ... | null | D.cs:366:27:366:30 | null | null | | D.cs:367:13:367:56 | ... && ... | true | D.cs:367:13:367:21 | ... > ... | true | | D.cs:367:13:367:56 | ... && ... | true | D.cs:367:27:367:55 | ... \|\| ... | true | | D.cs:367:27:367:27 | access to local variable b | non-null | D.cs:366:19:366:47 | ... ? ... : ... | non-null | @@ -1078,8 +1214,16 @@ | E.cs:13:13:13:18 | access to local variable haveA3 | true | E.cs:12:22:12:52 | ... && ... | true | | E.cs:19:13:19:30 | String s1 = ... | non-null | E.cs:19:13:19:14 | access to local variable s1 | non-null | | E.cs:19:13:19:30 | String s1 = ... | null | E.cs:19:13:19:14 | access to local variable s1 | null | +| E.cs:19:18:19:30 | ... ? ... : ... | non-null | E.cs:19:18:19:18 | access to parameter x | false | +| E.cs:19:18:19:30 | ... ? ... : ... | non-null | E.cs:19:29:19:30 | "" | non-null | +| E.cs:19:18:19:30 | ... ? ... : ... | null | E.cs:19:18:19:18 | access to parameter x | true | +| E.cs:19:18:19:30 | ... ? ... : ... | null | E.cs:19:22:19:25 | null | null | | E.cs:20:13:20:41 | String s2 = ... | non-null | E.cs:20:13:20:14 | access to local variable s2 | non-null | | E.cs:20:13:20:41 | String s2 = ... | null | E.cs:20:13:20:14 | access to local variable s2 | null | +| E.cs:20:18:20:41 | ... ? ... : ... | non-null | E.cs:20:19:20:28 | ... == ... | false | +| E.cs:20:18:20:41 | ... ? ... : ... | non-null | E.cs:20:40:20:41 | "" | non-null | +| E.cs:20:18:20:41 | ... ? ... : ... | null | E.cs:20:19:20:28 | ... == ... | true | +| E.cs:20:18:20:41 | ... ? ... : ... | null | E.cs:20:33:20:36 | null | null | | E.cs:20:19:20:20 | access to local variable s1 | non-null | E.cs:19:18:19:30 | ... ? ... : ... | non-null | | E.cs:20:19:20:20 | access to local variable s1 | null | E.cs:19:18:19:30 | ... ? ... : ... | null | | E.cs:20:19:20:28 | ... == ... | false | E.cs:19:18:19:18 | access to parameter x | false | @@ -1096,10 +1240,18 @@ | E.cs:23:13:23:30 | ... = ... | non-null | E.cs:23:18:23:30 | ... ? ... : ... | non-null | | E.cs:23:13:23:30 | ... = ... | null | E.cs:23:13:23:14 | access to local variable s1 | null | | E.cs:23:13:23:30 | ... = ... | null | E.cs:23:18:23:30 | ... ? ... : ... | null | +| E.cs:23:18:23:30 | ... ? ... : ... | non-null | E.cs:23:18:23:18 | access to parameter y | false | +| E.cs:23:18:23:30 | ... ? ... : ... | non-null | E.cs:23:29:23:30 | "" | non-null | +| E.cs:23:18:23:30 | ... ? ... : ... | null | E.cs:23:18:23:18 | access to parameter y | true | +| E.cs:23:18:23:30 | ... ? ... : ... | null | E.cs:23:22:23:25 | null | null | | E.cs:24:13:24:41 | ... = ... | non-null | E.cs:24:13:24:14 | access to local variable s2 | non-null | | E.cs:24:13:24:41 | ... = ... | non-null | E.cs:24:18:24:41 | ... ? ... : ... | non-null | | E.cs:24:13:24:41 | ... = ... | null | E.cs:24:13:24:14 | access to local variable s2 | null | | E.cs:24:13:24:41 | ... = ... | null | E.cs:24:18:24:41 | ... ? ... : ... | null | +| E.cs:24:18:24:41 | ... ? ... : ... | non-null | E.cs:24:19:24:28 | ... == ... | false | +| E.cs:24:18:24:41 | ... ? ... : ... | non-null | E.cs:24:40:24:41 | "" | non-null | +| E.cs:24:18:24:41 | ... ? ... : ... | null | E.cs:24:19:24:28 | ... == ... | true | +| E.cs:24:18:24:41 | ... ? ... : ... | null | E.cs:24:33:24:36 | null | null | | E.cs:24:19:24:20 | access to local variable s1 | non-null | E.cs:23:18:23:30 | ... ? ... : ... | non-null | | E.cs:24:19:24:20 | access to local variable s1 | null | E.cs:23:18:23:30 | ... ? ... : ... | null | | E.cs:24:19:24:28 | ... == ... | false | E.cs:23:18:23:18 | access to parameter y | false | @@ -1158,6 +1310,9 @@ | E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:83:29:83:30 | access to parameter b1 | true | | E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:85:18:85:29 | ... != ... | true | | E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:85:34:85:35 | access to parameter b2 | true | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | 1 | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | 2 | +| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | 3 | | E.cs:107:15:107:25 | Int32[] arr2 = ... | non-null | E.cs:107:15:107:18 | access to local variable arr2 | non-null | | E.cs:107:15:107:25 | Int32[] arr2 = ... | null | E.cs:107:15:107:18 | access to local variable arr2 | null | | E.cs:109:13:109:39 | ... = ... | non-null | E.cs:109:13:109:16 | access to local variable arr2 | non-null | @@ -1237,6 +1392,10 @@ | E.cs:193:19:193:29 | call to method ToString | non-null | E.cs:193:17:193:17 | access to parameter o | non-null | | E.cs:198:13:198:29 | String o = ... | non-null | E.cs:198:13:198:13 | access to local variable o | non-null | | E.cs:198:13:198:29 | String o = ... | null | E.cs:198:13:198:13 | access to local variable o | null | +| E.cs:198:17:198:29 | ... ? ... : ... | non-null | E.cs:198:17:198:17 | access to parameter b | false | +| E.cs:198:17:198:29 | ... ? ... : ... | non-null | E.cs:198:28:198:29 | "" | non-null | +| E.cs:198:17:198:29 | ... ? ... : ... | null | E.cs:198:17:198:17 | access to parameter b | true | +| E.cs:198:17:198:29 | ... ? ... : ... | null | E.cs:198:21:198:24 | null | null | | E.cs:199:9:199:9 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | | E.cs:199:9:199:9 | access to local variable o | null | E.cs:198:17:198:29 | ... ? ... : ... | null | | E.cs:201:11:201:11 | access to local variable o | non-null | E.cs:198:17:198:29 | ... ? ... : ... | non-null | @@ -1337,6 +1496,10 @@ | Forwarding.cs:83:16:83:24 | ... != ... | true | Forwarding.cs:83:16:83:16 | access to parameter o | non-null | | GuardedString.cs:7:16:7:32 | String s = ... | non-null | GuardedString.cs:7:16:7:16 | access to local variable s | non-null | | GuardedString.cs:7:16:7:32 | String s = ... | null | GuardedString.cs:7:16:7:16 | access to local variable s | null | +| GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | GuardedString.cs:7:20:7:20 | access to parameter b | false | +| GuardedString.cs:7:20:7:32 | ... ? ... : ... | non-null | GuardedString.cs:7:31:7:32 | "" | non-null | +| GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | GuardedString.cs:7:20:7:20 | access to parameter b | true | +| GuardedString.cs:7:20:7:32 | ... ? ... : ... | null | GuardedString.cs:7:24:7:27 | null | null | | GuardedString.cs:9:13:9:36 | !... | false | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | true | | GuardedString.cs:9:13:9:36 | !... | true | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | | GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | false | GuardedString.cs:7:20:7:20 | access to parameter b | false | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index 3af6e31daa5..61d873136c0 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -10,7 +10,6 @@ | D.cs:32:9:32:13 | access to parameter param | Variable '$@' may be null here as suggested by $@ null check. | D.cs:26:32:26:36 | param | param | D.cs:28:13:28:25 | ... != ... | this | | D.cs:62:13:62:14 | access to local variable o5 | Variable '$@' may be null here because of $@ assignment. | D.cs:58:13:58:14 | o5 | o5 | D.cs:58:13:58:41 | String o5 = ... | this | | D.cs:73:13:73:14 | access to local variable o7 | Variable '$@' may be null here because of $@ assignment. | D.cs:68:13:68:14 | o7 | o7 | D.cs:68:13:68:34 | String o7 = ... | this | -| D.cs:80:13:80:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | | D.cs:82:13:82:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | | D.cs:84:13:84:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | | D.cs:91:13:91:14 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | From 3bb3de23ce1948a94ed47437d16b3bcd8e6ce5e6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 4 Dec 2018 16:08:41 +0100 Subject: [PATCH 7/8] C#: Update change note --- change-notes/1.20/analysis-csharp.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/change-notes/1.20/analysis-csharp.md b/change-notes/1.20/analysis-csharp.md index 3fb6740fd76..13ec3648eb2 100644 --- a/change-notes/1.20/analysis-csharp.md +++ b/change-notes/1.20/analysis-csharp.md @@ -9,7 +9,8 @@ ## Changes to existing queries -| *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* | +| *@name of query (Query ID)* | *Impact on results* | *How/why the query has changed* | +|------------------------------|------------------------|-----------------------------------| | Off-by-one comparison against container length (cs/index-out-of-bounds) | Fewer false positives | Results have been removed when there are additional guards on the index. | | Dereferenced variable is always null (cs/dereferenced-value-is-always-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. | | Dereferenced variable may be null (cs/dereferenced-value-may-be-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. | From fce805834e662c88ea122243258ae92902a1fa17 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 7 Dec 2018 09:40:49 +0100 Subject: [PATCH 8/8] C#: Address review comments --- csharp/ql/src/CSI/NullAlways.qhelp | 6 +- csharp/ql/src/CSI/NullAlways.ql | 2 +- csharp/ql/src/CSI/NullMaybe.qhelp | 6 +- csharp/ql/src/CSI/NullMaybe.ql | 2 +- csharp/ql/test/query-tests/Nullness/B.cs | 4 +- .../query-tests/Nullness/NullAlways.expected | 76 ++++----- .../query-tests/Nullness/NullMaybe.expected | 146 +++++++++--------- 7 files changed, 121 insertions(+), 121 deletions(-) diff --git a/csharp/ql/src/CSI/NullAlways.qhelp b/csharp/ql/src/CSI/NullAlways.qhelp index 5d9fb4a78eb..c0b1d3447ef 100644 --- a/csharp/ql/src/CSI/NullAlways.qhelp +++ b/csharp/ql/src/CSI/NullAlways.qhelp @@ -5,9 +5,9 @@ -

    If a variable is dereferenced, and the variable has a null -value on all possible execution paths leading to the dereferencing, the dereferencing is -guaranteed to result in a NullReferenceException. +

    If a variable is dereferenced, for example as the qualifier in a method call, and the +variable has a null value on all possible execution paths leading to the +dereferencing, the dereferencing is guaranteed to result in a NullReferenceException.

    diff --git a/csharp/ql/src/CSI/NullAlways.ql b/csharp/ql/src/CSI/NullAlways.ql index 7bd40b38941..1c6ecf8997c 100644 --- a/csharp/ql/src/CSI/NullAlways.ql +++ b/csharp/ql/src/CSI/NullAlways.ql @@ -16,4 +16,4 @@ import semmle.code.csharp.dataflow.Nullness from Dereference d, Ssa::SourceVariable v where d.isFirstAlwaysNull(v) -select d, "Variable '$@' is always null here.", v, v.toString() +select d, "Variable $@ is always null here.", v, v.toString() diff --git a/csharp/ql/src/CSI/NullMaybe.qhelp b/csharp/ql/src/CSI/NullMaybe.qhelp index 5206268ebaf..b0b94d210ed 100644 --- a/csharp/ql/src/CSI/NullMaybe.qhelp +++ b/csharp/ql/src/CSI/NullMaybe.qhelp @@ -5,9 +5,9 @@ -

    If a variable is dereferenced, and the variable may have a null -value on some execution paths leading to the dereferencing, the dereferencing -may result in a NullReferenceException. +

    If a variable is dereferenced, for example as the qualifier in a method call, and the +variable may have a null value on some execution paths leading to the +dereferencing, the dereferencing may result in a NullReferenceException.

    diff --git a/csharp/ql/src/CSI/NullMaybe.ql b/csharp/ql/src/CSI/NullMaybe.ql index 1ee336e04a2..eaacd7fa3da 100644 --- a/csharp/ql/src/CSI/NullMaybe.ql +++ b/csharp/ql/src/CSI/NullMaybe.ql @@ -17,4 +17,4 @@ import semmle.code.csharp.dataflow.Nullness from Dereference d, Ssa::SourceVariable v, string msg, Element reason where d.isFirstMaybeNull(v.getAnSsaDefinition(), msg, reason) -select d, "Variable '$@' may be null here " + msg + ".", v, v.toString(), reason, "this" +select d, "Variable $@ may be null here " + msg + ".", v, v.toString(), reason, "this" diff --git a/csharp/ql/test/query-tests/Nullness/B.cs b/csharp/ql/test/query-tests/Nullness/B.cs index 0649a901277..76ebb6ffd8e 100644 --- a/csharp/ql/test/query-tests/Nullness/B.cs +++ b/csharp/ql/test/query-tests/Nullness/B.cs @@ -34,11 +34,11 @@ class B return !(b1 == b2); } - public struct CoOrds + public struct Coords { public int x, y; - public CoOrds(int p1, int p2) + public Coords(int p1, int p2) { x = p1; y = p2; diff --git a/csharp/ql/test/query-tests/Nullness/NullAlways.expected b/csharp/ql/test/query-tests/Nullness/NullAlways.expected index e2d358969c0..1e439a9c3e4 100644 --- a/csharp/ql/test/query-tests/Nullness/NullAlways.expected +++ b/csharp/ql/test/query-tests/Nullness/NullAlways.expected @@ -1,38 +1,38 @@ -| A.cs:8:15:8:32 | access to local variable synchronizedAlways | Variable '$@' is always null here. | A.cs:7:16:7:33 | synchronizedAlways | synchronizedAlways | -| A.cs:17:9:17:17 | access to local variable arrayNull | Variable '$@' is always null here. | A.cs:16:15:16:23 | arrayNull | arrayNull | -| A.cs:31:27:31:37 | access to local variable arrayAccess | Variable '$@' is always null here. | A.cs:26:15:26:25 | arrayAccess | arrayAccess | -| A.cs:32:27:32:37 | access to local variable fieldAccess | Variable '$@' is always null here. | A.cs:27:18:27:28 | fieldAccess | fieldAccess | -| A.cs:33:28:33:39 | access to local variable methodAccess | Variable '$@' is always null here. | A.cs:28:16:28:27 | methodAccess | methodAccess | -| A.cs:34:27:34:36 | access to local variable methodCall | Variable '$@' is always null here. | A.cs:29:16:29:25 | methodCall | methodCall | -| A.cs:50:9:50:14 | access to local variable varRef | Variable '$@' is always null here. | A.cs:48:16:48:21 | varRef | varRef | -| Assert.cs:15:27:15:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:23:27:23:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:31:27:31:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:47:27:47:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:51:27:51:27 | access to local variable s | Variable '$@' is always null here. | Assert.cs:9:16:9:16 | s | s | -| B.cs:13:13:13:24 | access to local variable eqCallAlways | Variable '$@' is always null here. | B.cs:7:11:7:22 | eqCallAlways | eqCallAlways | -| B.cs:24:13:24:25 | access to local variable neqCallAlways | Variable '$@' is always null here. | B.cs:10:11:10:23 | neqCallAlways | neqCallAlways | -| C.cs:18:13:18:13 | access to local variable o | Variable '$@' is always null here. | C.cs:10:16:10:16 | o | o | -| C.cs:42:9:42:9 | access to local variable s | Variable '$@' is always null here. | C.cs:40:13:40:13 | s | s | -| C.cs:57:9:57:10 | access to local variable o2 | Variable '$@' is always null here. | C.cs:55:13:55:14 | o2 | o2 | -| C.cs:163:13:163:13 | access to local variable s | Variable '$@' is always null here. | C.cs:152:13:152:13 | s | s | -| C.cs:171:13:171:13 | access to local variable s | Variable '$@' is always null here. | C.cs:152:13:152:13 | s | s | -| C.cs:197:13:197:13 | access to local variable s | Variable '$@' is always null here. | C.cs:186:13:186:13 | s | s | -| C.cs:219:13:219:13 | access to local variable s | Variable '$@' is always null here. | C.cs:211:13:211:13 | s | s | -| C.cs:234:9:234:9 | access to local variable s | Variable '$@' is always null here. | C.cs:229:16:229:16 | s | s | -| C.cs:238:13:238:13 | access to local variable s | Variable '$@' is always null here. | C.cs:229:16:229:16 | s | s | -| C.cs:250:9:250:9 | access to local variable a | Variable '$@' is always null here. | C.cs:249:15:249:15 | a | a | -| C.cs:261:9:261:10 | access to local variable ia | Variable '$@' is always null here. | C.cs:258:15:258:16 | ia | ia | -| C.cs:262:20:262:21 | access to local variable sa | Variable '$@' is always null here. | C.cs:259:18:259:19 | sa | sa | -| D.cs:120:13:120:13 | access to local variable x | Variable '$@' is always null here. | D.cs:117:13:117:13 | x | x | -| D.cs:197:13:197:13 | access to local variable o | Variable '$@' is always null here. | D.cs:195:13:195:13 | o | o | -| D.cs:207:17:207:17 | access to local variable e | Variable '$@' is always null here. | D.cs:204:26:204:26 | e | e | -| D.cs:217:13:217:14 | access to local variable o3 | Variable '$@' is always null here. | D.cs:215:13:215:14 | o3 | o3 | -| D.cs:222:13:222:14 | access to local variable o4 | Variable '$@' is always null here. | D.cs:220:13:220:14 | o4 | o4 | -| D.cs:385:13:385:15 | access to local variable ioe | Variable '$@' is always null here. | D.cs:378:19:378:21 | ioe | ioe | -| E.cs:210:16:210:16 | access to parameter s | Variable '$@' is always null here. | E.cs:206:28:206:28 | s | s | -| E.cs:220:13:220:13 | access to local variable x | Variable '$@' is always null here. | E.cs:215:13:215:13 | x | x | -| E.cs:229:13:229:13 | access to local variable x | Variable '$@' is always null here. | E.cs:225:13:225:13 | x | x | -| Forwarding.cs:36:31:36:31 | access to local variable s | Variable '$@' is always null here. | Forwarding.cs:7:16:7:16 | s | s | -| Forwarding.cs:40:27:40:27 | access to local variable s | Variable '$@' is always null here. | Forwarding.cs:7:16:7:16 | s | s | -| NullAlwaysBad.cs:9:30:9:30 | access to parameter s | Variable '$@' is always null here. | NullAlwaysBad.cs:7:29:7:29 | s | s | +| A.cs:8:15:8:32 | access to local variable synchronizedAlways | Variable $@ is always null here. | A.cs:7:16:7:33 | synchronizedAlways | synchronizedAlways | +| A.cs:17:9:17:17 | access to local variable arrayNull | Variable $@ is always null here. | A.cs:16:15:16:23 | arrayNull | arrayNull | +| A.cs:31:27:31:37 | access to local variable arrayAccess | Variable $@ is always null here. | A.cs:26:15:26:25 | arrayAccess | arrayAccess | +| A.cs:32:27:32:37 | access to local variable fieldAccess | Variable $@ is always null here. | A.cs:27:18:27:28 | fieldAccess | fieldAccess | +| A.cs:33:28:33:39 | access to local variable methodAccess | Variable $@ is always null here. | A.cs:28:16:28:27 | methodAccess | methodAccess | +| A.cs:34:27:34:36 | access to local variable methodCall | Variable $@ is always null here. | A.cs:29:16:29:25 | methodCall | methodCall | +| A.cs:50:9:50:14 | access to local variable varRef | Variable $@ is always null here. | A.cs:48:16:48:21 | varRef | varRef | +| Assert.cs:15:27:15:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:23:27:23:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:31:27:31:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:47:27:47:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:51:27:51:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| B.cs:13:13:13:24 | access to local variable eqCallAlways | Variable $@ is always null here. | B.cs:7:11:7:22 | eqCallAlways | eqCallAlways | +| B.cs:24:13:24:25 | access to local variable neqCallAlways | Variable $@ is always null here. | B.cs:10:11:10:23 | neqCallAlways | neqCallAlways | +| C.cs:18:13:18:13 | access to local variable o | Variable $@ is always null here. | C.cs:10:16:10:16 | o | o | +| C.cs:42:9:42:9 | access to local variable s | Variable $@ is always null here. | C.cs:40:13:40:13 | s | s | +| C.cs:57:9:57:10 | access to local variable o2 | Variable $@ is always null here. | C.cs:55:13:55:14 | o2 | o2 | +| C.cs:163:13:163:13 | access to local variable s | Variable $@ is always null here. | C.cs:152:13:152:13 | s | s | +| C.cs:171:13:171:13 | access to local variable s | Variable $@ is always null here. | C.cs:152:13:152:13 | s | s | +| C.cs:197:13:197:13 | access to local variable s | Variable $@ is always null here. | C.cs:186:13:186:13 | s | s | +| C.cs:219:13:219:13 | access to local variable s | Variable $@ is always null here. | C.cs:211:13:211:13 | s | s | +| C.cs:234:9:234:9 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s | +| C.cs:238:13:238:13 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s | +| C.cs:250:9:250:9 | access to local variable a | Variable $@ is always null here. | C.cs:249:15:249:15 | a | a | +| C.cs:261:9:261:10 | access to local variable ia | Variable $@ is always null here. | C.cs:258:15:258:16 | ia | ia | +| C.cs:262:20:262:21 | access to local variable sa | Variable $@ is always null here. | C.cs:259:18:259:19 | sa | sa | +| D.cs:120:13:120:13 | access to local variable x | Variable $@ is always null here. | D.cs:117:13:117:13 | x | x | +| D.cs:197:13:197:13 | access to local variable o | Variable $@ is always null here. | D.cs:195:13:195:13 | o | o | +| D.cs:207:17:207:17 | access to local variable e | Variable $@ is always null here. | D.cs:204:26:204:26 | e | e | +| D.cs:217:13:217:14 | access to local variable o3 | Variable $@ is always null here. | D.cs:215:13:215:14 | o3 | o3 | +| D.cs:222:13:222:14 | access to local variable o4 | Variable $@ is always null here. | D.cs:220:13:220:14 | o4 | o4 | +| D.cs:385:13:385:15 | access to local variable ioe | Variable $@ is always null here. | D.cs:378:19:378:21 | ioe | ioe | +| E.cs:210:16:210:16 | access to parameter s | Variable $@ is always null here. | E.cs:206:28:206:28 | s | s | +| E.cs:220:13:220:13 | access to local variable x | Variable $@ is always null here. | E.cs:215:13:215:13 | x | x | +| E.cs:229:13:229:13 | access to local variable x | Variable $@ is always null here. | E.cs:225:13:225:13 | x | x | +| Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s | +| Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s | +| NullAlwaysBad.cs:9:30:9:30 | access to parameter s | Variable $@ is always null here. | NullAlwaysBad.cs:7:29:7:29 | s | s | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index 61d873136c0..c3ef73a7532 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -1,73 +1,73 @@ -| C.cs:64:9:64:10 | access to local variable o1 | Variable '$@' may be null here because of $@ assignment. | C.cs:62:13:62:14 | o1 | o1 | C.cs:62:13:62:46 | Object o1 = ... | this | -| C.cs:68:9:68:10 | access to local variable o2 | Variable '$@' may be null here because of $@ assignment. | C.cs:66:13:66:14 | o2 | o2 | C.cs:66:13:66:46 | Object o2 = ... | this | -| C.cs:96:15:96:15 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | C.cs:95:13:95:13 | o | o | C.cs:95:13:95:45 | Object o = ... | this | -| C.cs:104:27:104:30 | access to parameter list | Variable '$@' may be null here because of $@ assignment. | C.cs:100:42:100:45 | list | list | C.cs:103:13:103:23 | ... = ... | this | -| C.cs:178:13:178:13 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:152:13:152:13 | s | s | C.cs:179:13:179:20 | ... = ... | this | -| C.cs:204:13:204:13 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:186:13:186:13 | s | s | C.cs:205:13:205:20 | ... = ... | this | -| C.cs:224:9:224:9 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:211:13:211:13 | s | s | C.cs:223:13:223:20 | ... = ... | this | -| C.cs:243:13:243:13 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | C.cs:229:16:229:16 | s | s | C.cs:241:24:241:31 | ... = ... | this | -| D.cs:23:9:23:13 | access to parameter param | Variable '$@' may be null here because of $@ null argument. | D.cs:21:32:21:36 | param | param | D.cs:17:17:17:20 | null | this | -| D.cs:32:9:32:13 | access to parameter param | Variable '$@' may be null here as suggested by $@ null check. | D.cs:26:32:26:36 | param | param | D.cs:28:13:28:25 | ... != ... | this | -| D.cs:62:13:62:14 | access to local variable o5 | Variable '$@' may be null here because of $@ assignment. | D.cs:58:13:58:14 | o5 | o5 | D.cs:58:13:58:41 | String o5 = ... | this | -| D.cs:73:13:73:14 | access to local variable o7 | Variable '$@' may be null here because of $@ assignment. | D.cs:68:13:68:14 | o7 | o7 | D.cs:68:13:68:34 | String o7 = ... | this | -| D.cs:82:13:82:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | -| D.cs:84:13:84:14 | access to local variable o8 | Variable '$@' may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | -| D.cs:91:13:91:14 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | -| D.cs:94:21:94:22 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | -| D.cs:98:21:98:22 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | -| D.cs:102:31:102:32 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | -| D.cs:105:19:105:20 | access to local variable xs | Variable '$@' may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | -| D.cs:134:24:134:24 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this | -| D.cs:134:24:134:24 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this | -| D.cs:135:24:135:24 | access to parameter b | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:44:125:44 | b | b | D.cs:128:20:128:28 | ... == ... | this | -| D.cs:145:20:145:20 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this | -| D.cs:145:20:145:20 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this | -| D.cs:151:9:151:11 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | D.cs:149:36:149:38 | obj | obj | D.cs:152:17:152:27 | ... != ... | this | -| D.cs:171:9:171:11 | access to local variable obj | Variable '$@' may be null here because of $@ assignment. | D.cs:163:16:163:18 | obj | obj | D.cs:163:16:163:25 | Object obj = ... | this | -| D.cs:245:13:245:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this | -| D.cs:247:13:247:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this | -| D.cs:253:13:253:14 | access to local variable o2 | Variable '$@' may be null here because of $@ assignment. | D.cs:249:13:249:14 | o2 | o2 | D.cs:249:13:249:38 | String o2 = ... | this | -| D.cs:267:13:267:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:258:16:258:23 | Object o = ... | this | -| D.cs:291:13:291:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this | -| D.cs:291:13:291:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this | -| D.cs:294:13:294:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this | -| D.cs:294:13:294:13 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this | -| D.cs:300:17:300:20 | access to local variable prev | Variable '$@' may be null here because of $@ assignment. | D.cs:296:16:296:19 | prev | prev | D.cs:296:16:296:26 | Object prev = ... | this | -| D.cs:313:17:313:17 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | D.cs:304:16:304:16 | s | s | D.cs:304:16:304:23 | String s = ... | this | -| D.cs:324:9:324:9 | access to local variable r | Variable '$@' may be null here because of $@ assignment. | D.cs:316:16:316:16 | r | r | D.cs:316:16:316:23 | Object r = ... | this | -| D.cs:356:13:356:13 | access to local variable a | Variable '$@' may be null here because of $@ assignment. | D.cs:351:15:351:15 | a | a | D.cs:351:15:351:22 | Int32[] a = ... | this | -| D.cs:363:13:363:16 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | D.cs:360:20:360:23 | last | last | D.cs:360:20:360:30 | String last = ... | this | -| D.cs:372:13:372:13 | access to local variable b | Variable '$@' may be null here because of $@ assignment. | D.cs:366:15:366:15 | b | b | D.cs:366:15:366:47 | Int32[] b = ... | this | -| D.cs:395:20:395:20 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | D.cs:388:36:388:36 | a | a | D.cs:390:20:390:28 | ... == ... | this | -| D.cs:400:20:400:20 | access to parameter b | Variable '$@' may be null here as suggested by $@ null check. | D.cs:388:45:388:45 | b | b | D.cs:397:20:397:28 | ... == ... | this | -| D.cs:410:13:410:13 | access to parameter y | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:27:407:35 | ... == ... | this | -| D.cs:410:13:410:13 | access to parameter y | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:55:407:63 | ... != ... | this | -| D.cs:410:13:410:13 | access to parameter y | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:411:13:411:21 | ... != ... | this | -| D.cs:412:13:412:13 | access to parameter x | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:14:407:22 | ... != ... | this | -| D.cs:412:13:412:13 | access to parameter x | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:42:407:50 | ... == ... | this | -| D.cs:412:13:412:13 | access to parameter x | Variable '$@' may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:409:13:409:21 | ... != ... | this | -| E.cs:12:38:12:39 | access to local variable a2 | Variable '$@' may be null here because of $@ assignment. | E.cs:9:18:9:19 | a2 | a2 | E.cs:9:18:9:26 | Int64[][] a2 = ... | this | -| E.cs:14:13:14:14 | access to local variable a3 | Variable '$@' may be null here because of $@ assignment. | E.cs:11:16:11:17 | a3 | a3 | E.cs:11:16:11:24 | Int64[] a3 = ... | this | -| E.cs:27:13:27:14 | access to local variable s1 | Variable '$@' may be null here because of $@ assignment. | E.cs:19:13:19:14 | s1 | s1 | E.cs:23:13:23:30 | ... = ... | this | -| E.cs:35:9:35:12 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:32:16:32:26 | String last = ... | this | -| E.cs:43:13:43:16 | access to local variable last | Variable '$@' may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:37:9:37:19 | ... = ... | this | -| E.cs:61:13:61:17 | access to local variable slice | Variable '$@' may be null here because of $@ assignment. | E.cs:51:22:51:26 | slice | slice | E.cs:51:22:51:33 | List slice = ... | this | -| E.cs:73:13:73:15 | access to parameter arr | Variable '$@' may be null here as suggested by $@ null check. | E.cs:66:40:66:42 | arr | arr | E.cs:70:22:70:32 | ... == ... | this | -| E.cs:112:13:112:16 | access to local variable arr2 | Variable '$@' may be null here because of $@ assignment. | E.cs:107:15:107:18 | arr2 | arr2 | E.cs:107:15:107:25 | Int32[] arr2 = ... | this | -| E.cs:125:33:125:35 | access to local variable obj | Variable '$@' may be null here because of $@ assignment. | E.cs:119:13:119:15 | obj | obj | E.cs:137:25:137:34 | ... = ... | this | -| E.cs:159:13:159:16 | access to local variable obj2 | Variable '$@' may be null here as suggested by $@ null check. | E.cs:152:16:152:19 | obj2 | obj2 | E.cs:153:13:153:24 | ... != ... | this | -| E.cs:167:21:167:21 | access to parameter a | Variable '$@' may be null here as suggested by $@ null check. | E.cs:162:28:162:28 | a | a | E.cs:164:17:164:25 | ... == ... | this | -| E.cs:178:13:178:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this | -| E.cs:178:13:178:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this | -| E.cs:186:13:186:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this | -| E.cs:186:13:186:15 | access to parameter obj | Variable '$@' may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this | -| E.cs:192:17:192:17 | access to parameter o | Variable '$@' may be null here as suggested by $@ null check. | E.cs:190:29:190:29 | o | o | E.cs:193:17:193:17 | access to parameter o | this | -| E.cs:201:11:201:11 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this | -| E.cs:203:11:203:11 | access to local variable o | Variable '$@' may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this | -| E.cs:218:9:218:9 | access to local variable x | Variable '$@' may be null here because of $@ assignment. | E.cs:215:13:215:13 | x | x | E.cs:217:13:217:20 | ... = ... | this | -| E.cs:230:9:230:9 | access to local variable x | Variable '$@' may be null here because of $@ assignment. | E.cs:225:13:225:13 | x | x | E.cs:227:13:227:20 | ... = ... | this | -| E.cs:235:16:235:16 | access to parameter i | Variable '$@' may be null here because it has a nullable type. | E.cs:233:26:233:26 | i | i | E.cs:233:26:233:26 | i | this | -| E.cs:240:21:240:21 | access to parameter i | Variable '$@' may be null here because it has a nullable type. | E.cs:238:26:238:26 | i | i | E.cs:238:26:238:26 | i | this | -| GuardedString.cs:35:31:35:31 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this | -| NullMaybeBad.cs:9:31:9:31 | access to parameter o | Variable '$@' may be null here because of $@ null argument. | NullMaybeBad.cs:7:29:7:29 | o | o | NullMaybeBad.cs:15:21:15:24 | null | this | -| StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable '$@' may be null here because of $@ assignment. | StringConcatenation.cs:14:16:14:16 | s | s | StringConcatenation.cs:14:16:14:23 | String s = ... | this | +| C.cs:64:9:64:10 | access to local variable o1 | Variable $@ may be null here because of $@ assignment. | C.cs:62:13:62:14 | o1 | o1 | C.cs:62:13:62:46 | Object o1 = ... | this | +| C.cs:68:9:68:10 | access to local variable o2 | Variable $@ may be null here because of $@ assignment. | C.cs:66:13:66:14 | o2 | o2 | C.cs:66:13:66:46 | Object o2 = ... | this | +| C.cs:96:15:96:15 | access to local variable o | Variable $@ may be null here because of $@ assignment. | C.cs:95:13:95:13 | o | o | C.cs:95:13:95:45 | Object o = ... | this | +| C.cs:104:27:104:30 | access to parameter list | Variable $@ may be null here because of $@ assignment. | C.cs:100:42:100:45 | list | list | C.cs:103:13:103:23 | ... = ... | this | +| C.cs:178:13:178:13 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:152:13:152:13 | s | s | C.cs:179:13:179:20 | ... = ... | this | +| C.cs:204:13:204:13 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:186:13:186:13 | s | s | C.cs:205:13:205:20 | ... = ... | this | +| C.cs:224:9:224:9 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:211:13:211:13 | s | s | C.cs:223:13:223:20 | ... = ... | this | +| C.cs:243:13:243:13 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:229:16:229:16 | s | s | C.cs:241:24:241:31 | ... = ... | this | +| D.cs:23:9:23:13 | access to parameter param | Variable $@ may be null here because of $@ null argument. | D.cs:21:32:21:36 | param | param | D.cs:17:17:17:20 | null | this | +| D.cs:32:9:32:13 | access to parameter param | Variable $@ may be null here as suggested by $@ null check. | D.cs:26:32:26:36 | param | param | D.cs:28:13:28:25 | ... != ... | this | +| D.cs:62:13:62:14 | access to local variable o5 | Variable $@ may be null here because of $@ assignment. | D.cs:58:13:58:14 | o5 | o5 | D.cs:58:13:58:41 | String o5 = ... | this | +| D.cs:73:13:73:14 | access to local variable o7 | Variable $@ may be null here because of $@ assignment. | D.cs:68:13:68:14 | o7 | o7 | D.cs:68:13:68:34 | String o7 = ... | this | +| D.cs:82:13:82:14 | access to local variable o8 | Variable $@ may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | +| D.cs:84:13:84:14 | access to local variable o8 | Variable $@ may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this | +| D.cs:91:13:91:14 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:94:21:94:22 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:98:21:98:22 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:102:31:102:32 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:105:19:105:20 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this | +| D.cs:134:24:134:24 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this | +| D.cs:134:24:134:24 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this | +| D.cs:135:24:135:24 | access to parameter b | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:44:125:44 | b | b | D.cs:128:20:128:28 | ... == ... | this | +| D.cs:145:20:145:20 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this | +| D.cs:145:20:145:20 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this | +| D.cs:151:9:151:11 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | D.cs:149:36:149:38 | obj | obj | D.cs:152:17:152:27 | ... != ... | this | +| D.cs:171:9:171:11 | access to local variable obj | Variable $@ may be null here because of $@ assignment. | D.cs:163:16:163:18 | obj | obj | D.cs:163:16:163:25 | Object obj = ... | this | +| D.cs:245:13:245:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this | +| D.cs:247:13:247:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this | +| D.cs:253:13:253:14 | access to local variable o2 | Variable $@ may be null here because of $@ assignment. | D.cs:249:13:249:14 | o2 | o2 | D.cs:249:13:249:38 | String o2 = ... | this | +| D.cs:267:13:267:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:258:16:258:23 | Object o = ... | this | +| D.cs:291:13:291:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this | +| D.cs:291:13:291:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this | +| D.cs:294:13:294:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this | +| D.cs:294:13:294:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this | +| D.cs:300:17:300:20 | access to local variable prev | Variable $@ may be null here because of $@ assignment. | D.cs:296:16:296:19 | prev | prev | D.cs:296:16:296:26 | Object prev = ... | this | +| D.cs:313:17:313:17 | access to local variable s | Variable $@ may be null here because of $@ assignment. | D.cs:304:16:304:16 | s | s | D.cs:304:16:304:23 | String s = ... | this | +| D.cs:324:9:324:9 | access to local variable r | Variable $@ may be null here because of $@ assignment. | D.cs:316:16:316:16 | r | r | D.cs:316:16:316:23 | Object r = ... | this | +| D.cs:356:13:356:13 | access to local variable a | Variable $@ may be null here because of $@ assignment. | D.cs:351:15:351:15 | a | a | D.cs:351:15:351:22 | Int32[] a = ... | this | +| D.cs:363:13:363:16 | access to local variable last | Variable $@ may be null here because of $@ assignment. | D.cs:360:20:360:23 | last | last | D.cs:360:20:360:30 | String last = ... | this | +| D.cs:372:13:372:13 | access to local variable b | Variable $@ may be null here because of $@ assignment. | D.cs:366:15:366:15 | b | b | D.cs:366:15:366:47 | Int32[] b = ... | this | +| D.cs:395:20:395:20 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:388:36:388:36 | a | a | D.cs:390:20:390:28 | ... == ... | this | +| D.cs:400:20:400:20 | access to parameter b | Variable $@ may be null here as suggested by $@ null check. | D.cs:388:45:388:45 | b | b | D.cs:397:20:397:28 | ... == ... | this | +| D.cs:410:13:410:13 | access to parameter y | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:27:407:35 | ... == ... | this | +| D.cs:410:13:410:13 | access to parameter y | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:55:407:63 | ... != ... | this | +| D.cs:410:13:410:13 | access to parameter y | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:411:13:411:21 | ... != ... | this | +| D.cs:412:13:412:13 | access to parameter x | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:14:407:22 | ... != ... | this | +| D.cs:412:13:412:13 | access to parameter x | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:42:407:50 | ... == ... | this | +| D.cs:412:13:412:13 | access to parameter x | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:409:13:409:21 | ... != ... | this | +| E.cs:12:38:12:39 | access to local variable a2 | Variable $@ may be null here because of $@ assignment. | E.cs:9:18:9:19 | a2 | a2 | E.cs:9:18:9:26 | Int64[][] a2 = ... | this | +| E.cs:14:13:14:14 | access to local variable a3 | Variable $@ may be null here because of $@ assignment. | E.cs:11:16:11:17 | a3 | a3 | E.cs:11:16:11:24 | Int64[] a3 = ... | this | +| E.cs:27:13:27:14 | access to local variable s1 | Variable $@ may be null here because of $@ assignment. | E.cs:19:13:19:14 | s1 | s1 | E.cs:23:13:23:30 | ... = ... | this | +| E.cs:35:9:35:12 | access to local variable last | Variable $@ may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:32:16:32:26 | String last = ... | this | +| E.cs:43:13:43:16 | access to local variable last | Variable $@ may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:37:9:37:19 | ... = ... | this | +| E.cs:61:13:61:17 | access to local variable slice | Variable $@ may be null here because of $@ assignment. | E.cs:51:22:51:26 | slice | slice | E.cs:51:22:51:33 | List slice = ... | this | +| E.cs:73:13:73:15 | access to parameter arr | Variable $@ may be null here as suggested by $@ null check. | E.cs:66:40:66:42 | arr | arr | E.cs:70:22:70:32 | ... == ... | this | +| E.cs:112:13:112:16 | access to local variable arr2 | Variable $@ may be null here because of $@ assignment. | E.cs:107:15:107:18 | arr2 | arr2 | E.cs:107:15:107:25 | Int32[] arr2 = ... | this | +| E.cs:125:33:125:35 | access to local variable obj | Variable $@ may be null here because of $@ assignment. | E.cs:119:13:119:15 | obj | obj | E.cs:137:25:137:34 | ... = ... | this | +| E.cs:159:13:159:16 | access to local variable obj2 | Variable $@ may be null here as suggested by $@ null check. | E.cs:152:16:152:19 | obj2 | obj2 | E.cs:153:13:153:24 | ... != ... | this | +| E.cs:167:21:167:21 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | E.cs:162:28:162:28 | a | a | E.cs:164:17:164:25 | ... == ... | this | +| E.cs:178:13:178:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this | +| E.cs:178:13:178:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this | +| E.cs:186:13:186:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this | +| E.cs:186:13:186:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this | +| E.cs:192:17:192:17 | access to parameter o | Variable $@ may be null here as suggested by $@ null check. | E.cs:190:29:190:29 | o | o | E.cs:193:17:193:17 | access to parameter o | this | +| E.cs:201:11:201:11 | access to local variable o | Variable $@ may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this | +| E.cs:203:11:203:11 | access to local variable o | Variable $@ may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this | +| E.cs:218:9:218:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:215:13:215:13 | x | x | E.cs:217:13:217:20 | ... = ... | this | +| E.cs:230:9:230:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:225:13:225:13 | x | x | E.cs:227:13:227:20 | ... = ... | this | +| E.cs:235:16:235:16 | access to parameter i | Variable $@ may be null here because it has a nullable type. | E.cs:233:26:233:26 | i | i | E.cs:233:26:233:26 | i | this | +| E.cs:240:21:240:21 | access to parameter i | Variable $@ may be null here because it has a nullable type. | E.cs:238:26:238:26 | i | i | E.cs:238:26:238:26 | i | this | +| GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this | +| NullMaybeBad.cs:9:31:9:31 | access to parameter o | Variable $@ may be null here because of $@ null argument. | NullMaybeBad.cs:7:29:7:29 | o | o | NullMaybeBad.cs:15:21:15:24 | null | this | +| StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable $@ may be null here because of $@ assignment. | StringConcatenation.cs:14:16:14:16 | s | s | StringConcatenation.cs:14:16:14:23 | String s = ... | this |