From 2a54dce5cbb1877b30c5763b4f9c9d65cef018ed Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 30 Mar 2026 11:44:02 +0200 Subject: [PATCH] C#: Remove redundant ConstantComparison.ql query. --- .../csharp-code-quality-extended.qls.expected | 1 - .../csharp-code-quality.qls.expected | 1 - .../csharp-security-and-quality.qls.expected | 1 - .../semmle/code/csharp/commons/Constants.qll | 13 ----- csharp/ql/src/CSI/CompareIdenticalValues.ql | 3 +- .../ql/src/Likely Bugs/ConstantComparison.cs | 2 - .../src/Likely Bugs/ConstantComparison.qhelp | 46 ---------------- .../ql/src/Likely Bugs/ConstantComparison.ql | 22 -------- .../csharp-security-and-quality.qls | 1 - .../ConstantCondition}/ConstantComparison.cs | 54 +++++++++---------- .../ConstantCondition.expected | 26 +++++++++ .../ConstantComparison.expected | 26 --------- .../ConstantComparison.qlref | 1 - .../Likely Bugs/ConstantComparison/options | 2 - 14 files changed, 54 insertions(+), 145 deletions(-) delete mode 100644 csharp/ql/src/Likely Bugs/ConstantComparison.cs delete mode 100644 csharp/ql/src/Likely Bugs/ConstantComparison.qhelp delete mode 100644 csharp/ql/src/Likely Bugs/ConstantComparison.ql rename csharp/ql/test/query-tests/{Likely Bugs/ConstantComparison => Bad Practices/Control-Flow/ConstantCondition}/ConstantComparison.cs (52%) delete mode 100644 csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.expected delete mode 100644 csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.qlref delete mode 100644 csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/options diff --git a/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality-extended.qls.expected b/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality-extended.qls.expected index fdc5e6eae9d..c6361fe69c5 100644 --- a/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality-extended.qls.expected +++ b/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality-extended.qls.expected @@ -65,7 +65,6 @@ ql/csharp/ql/src/Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql ql/csharp/ql/src/Likely Bugs/Collections/ContainerSizeCmpZero.ql ql/csharp/ql/src/Likely Bugs/Collections/ReadOnlyContainer.ql ql/csharp/ql/src/Likely Bugs/Collections/WriteOnlyContainer.ql -ql/csharp/ql/src/Likely Bugs/ConstantComparison.ql ql/csharp/ql/src/Likely Bugs/DangerousNonShortCircuitLogic.ql ql/csharp/ql/src/Likely Bugs/Dynamic/BadDynamicCall.ql ql/csharp/ql/src/Likely Bugs/EqualityCheckOnFloats.ql diff --git a/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality.qls.expected b/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality.qls.expected index 6694cc8461b..893eaeb7560 100644 --- a/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality.qls.expected +++ b/csharp/ql/integration-tests/posix/query-suite/csharp-code-quality.qls.expected @@ -38,7 +38,6 @@ ql/csharp/ql/src/Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql ql/csharp/ql/src/Likely Bugs/Collections/ContainerSizeCmpZero.ql ql/csharp/ql/src/Likely Bugs/Collections/ReadOnlyContainer.ql ql/csharp/ql/src/Likely Bugs/Collections/WriteOnlyContainer.ql -ql/csharp/ql/src/Likely Bugs/ConstantComparison.ql ql/csharp/ql/src/Likely Bugs/DangerousNonShortCircuitLogic.ql ql/csharp/ql/src/Likely Bugs/EqualityCheckOnFloats.ql ql/csharp/ql/src/Likely Bugs/EqualsArray.ql diff --git a/csharp/ql/integration-tests/posix/query-suite/csharp-security-and-quality.qls.expected b/csharp/ql/integration-tests/posix/query-suite/csharp-security-and-quality.qls.expected index b520a571fc8..43c14b4281c 100644 --- a/csharp/ql/integration-tests/posix/query-suite/csharp-security-and-quality.qls.expected +++ b/csharp/ql/integration-tests/posix/query-suite/csharp-security-and-quality.qls.expected @@ -69,7 +69,6 @@ ql/csharp/ql/src/Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql ql/csharp/ql/src/Likely Bugs/Collections/ContainerSizeCmpZero.ql ql/csharp/ql/src/Likely Bugs/Collections/ReadOnlyContainer.ql ql/csharp/ql/src/Likely Bugs/Collections/WriteOnlyContainer.ql -ql/csharp/ql/src/Likely Bugs/ConstantComparison.ql ql/csharp/ql/src/Likely Bugs/DangerousNonShortCircuitLogic.ql ql/csharp/ql/src/Likely Bugs/Dynamic/BadDynamicCall.ql ql/csharp/ql/src/Likely Bugs/EqualityCheckOnFloats.ql diff --git a/csharp/ql/lib/semmle/code/csharp/commons/Constants.qll b/csharp/ql/lib/semmle/code/csharp/commons/Constants.qll index ab2d9e0eef7..5025202eb21 100644 --- a/csharp/ql/lib/semmle/code/csharp/commons/Constants.qll +++ b/csharp/ql/lib/semmle/code/csharp/commons/Constants.qll @@ -4,19 +4,6 @@ import csharp private import semmle.code.csharp.commons.ComparisonTest private import semmle.code.csharp.commons.StructuralComparison as StructuralComparison -pragma[noinline] -private predicate isConstantCondition0(ControlFlow::Node cfn, boolean b) { - exists(cfn.getASuccessorByType(any(ControlFlow::BooleanSuccessor t | t.getValue() = b))) and - strictcount(ControlFlow::SuccessorType t | exists(cfn.getASuccessorByType(t))) = 1 -} - -/** - * Holds if `e` is a condition that always evaluates to Boolean value `b`. - */ -predicate isConstantCondition(Expr e, boolean b) { - forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() | isConstantCondition0(cfn, b)) -} - /** * Holds if comparison operation `co` is constant with the Boolean value `b`. * For example, the comparison `x > x` is constantly `false` in diff --git a/csharp/ql/src/CSI/CompareIdenticalValues.ql b/csharp/ql/src/CSI/CompareIdenticalValues.ql index 503067a8a3e..fe79db08206 100644 --- a/csharp/ql/src/CSI/CompareIdenticalValues.ql +++ b/csharp/ql/src/CSI/CompareIdenticalValues.ql @@ -47,7 +47,6 @@ where not comparesIdenticalValuesNan(ct, _) and msg = "Comparison of identical values." ) and not isMutatingOperation(ct.getAnArgument().getAChild*()) and - not isConstantCondition(e, _) and // Avoid overlap with cs/constant-condition - not isConstantComparison(e, _) and // Avoid overlap with cs/constant-comparison + not isConstantComparison(e, _) and // Avoid overlap with cs/constant-condition not isExprInAssertion(e) select ct, msg diff --git a/csharp/ql/src/Likely Bugs/ConstantComparison.cs b/csharp/ql/src/Likely Bugs/ConstantComparison.cs deleted file mode 100644 index 5b0304b2818..00000000000 --- a/csharp/ql/src/Likely Bugs/ConstantComparison.cs +++ /dev/null @@ -1,2 +0,0 @@ - for (uint order = numberOfOrders; order >= 0; order--) - ProcessOrder(order); diff --git a/csharp/ql/src/Likely Bugs/ConstantComparison.qhelp b/csharp/ql/src/Likely Bugs/ConstantComparison.qhelp deleted file mode 100644 index 5e52142c84e..00000000000 --- a/csharp/ql/src/Likely Bugs/ConstantComparison.qhelp +++ /dev/null @@ -1,46 +0,0 @@ - - - -

- Comparisons which always yield the same result are unnecessary and may indicate a bug in the - logic. This can happen when the data type of one of the operands has a limited range of values. - For example unsigned integers are always greater than or equal to zero, and byte - values are always less than 256. -

- -

The following expressions always have the same result:

-
    -
  • Unsigned < 0 is always false,
  • -
  • 0 > Unsigned is always false,
  • -
  • 0 ≤ Unsigned is always true,
  • -
  • Unsigned ≥ 0 is always true,
  • -
  • Unsigned == -1 is always false,
  • -
  • Byte < 512 is always true.
  • -
-
- - -

- Examine the logic of the program to determine whether the comparison is necessary. - Either change the data types, or remove the unnecessary code. -

-
- - -

The following example attempts to count down from numberOfOrders to 0, - however the loop never terminates because order is an unsigned integer and so the - condition order >= 0 is always true.

- - - -

The solution is to change the type of the variable order.

-
- - -
  • - MSDN Library: C# Operators. -
  • -
    -
    \ No newline at end of file diff --git a/csharp/ql/src/Likely Bugs/ConstantComparison.ql b/csharp/ql/src/Likely Bugs/ConstantComparison.ql deleted file mode 100644 index 98352348214..00000000000 --- a/csharp/ql/src/Likely Bugs/ConstantComparison.ql +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @name Comparison is constant - * @description The result of the comparison is always the same. - * @kind problem - * @problem.severity warning - * @precision high - * @id cs/constant-comparison - * @tags quality - * reliability - * correctness - */ - -import csharp -import semmle.code.csharp.commons.Assertions -import semmle.code.csharp.commons.Constants - -from ComparisonOperation cmp, boolean value -where - isConstantComparison(cmp, value) and - not isConstantCondition(cmp, _) and // Avoid overlap with cs/constant-condition - not isExprInAssertion(cmp) -select cmp, "This comparison is always " + value + "." diff --git a/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls index 21d39db383d..9700c8b0341 100644 --- a/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls +++ b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls @@ -22,7 +22,6 @@ - cs/comparison-of-identical-expressions - cs/complex-block - cs/complex-condition - - cs/constant-comparison - cs/constant-condition - cs/coupled-types - cs/dereferenced-value-is-always-null diff --git a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.cs b/csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantComparison.cs similarity index 52% rename from csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.cs rename to csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantComparison.cs index c31d940e7f2..26f2c457325 100644 --- a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.cs +++ b/csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantComparison.cs @@ -16,16 +16,16 @@ class Test { bool good, bad; - bad = uintValue < 0; - bad = 0 > uintValue; - bad = 0 <= uintValue; - bad = uintValue >= 0; + bad = uintValue < 0; // $ Alert + bad = 0 > uintValue; // $ Alert + bad = 0 <= uintValue; // $ Alert + bad = uintValue >= 0; // $ Alert - bad = uintValue == -1; - bad = uintValue != -1; - bad = 256 == byteValue; - bad = 256 != byteValue; - bad = 1 != 0; + bad = uintValue == -1; // $ Alert + bad = uintValue != -1; // $ Alert + bad = 256 == byteValue; // $ Alert + bad = 256 != byteValue; // $ Alert + bad = 1 != 0; // $ Alert good = byteValue == 50; good = 50 != byteValue; @@ -35,61 +35,61 @@ class Test good = intValue <= 1u; good = 1u >= intValue; - good = charValue >= '0'; // Regression + good = charValue >= '0'; good = charValue < '0'; // Test ranges - bad = charValue <= 65535; - bad = charValue >= 0; + bad = charValue <= 65535; // $ Alert + bad = charValue >= 0; // $ Alert good = charValue < 255; good = charValue > 0; - bad = byteValue >= byte.MinValue; - bad = byteValue <= byte.MaxValue; + bad = byteValue >= byte.MinValue; // $ Alert + bad = byteValue <= byte.MaxValue; // $ Alert good = byteValue > byte.MinValue; good = byteValue < byte.MaxValue; - bad = sbyteValue >= sbyte.MinValue; - bad = sbyteValue <= sbyte.MaxValue; + bad = sbyteValue >= sbyte.MinValue; // $ Alert + bad = sbyteValue <= sbyte.MaxValue; // $ Alert good = sbyteValue < sbyte.MaxValue; good = sbyteValue > sbyte.MinValue; - bad = shortValue >= short.MinValue; - bad = shortValue <= short.MaxValue; + bad = shortValue >= short.MinValue; // $ Alert + bad = shortValue <= short.MaxValue; // $ Alert good = shortValue > short.MinValue; good = shortValue < short.MaxValue; - bad = ushortValue >= ushort.MinValue; - bad = ushortValue <= ushort.MaxValue; + bad = ushortValue >= ushort.MinValue; // $ Alert + bad = ushortValue <= ushort.MaxValue; // $ Alert good = ushortValue > ushort.MinValue; good = ushortValue < ushort.MaxValue; - bad = intValue >= int.MinValue; - bad = intValue <= int.MaxValue; + bad = intValue >= int.MinValue; // $ Alert + bad = intValue <= int.MaxValue; // $ Alert good = intValue > int.MinValue; good = intValue < int.MaxValue; - bad = uintValue >= uint.MinValue; + bad = uintValue >= uint.MinValue; // $ Alert good = uintValue > uint.MinValue; - bad = ulongValue >= ulong.MinValue; + bad = ulongValue >= ulong.MinValue; // $ Alert good = ulongValue > ulong.MinValue; // Explicit casts can cause large values to be truncated or // to wrap into negative values. good = (sbyte)byteValue >= 0; good = (sbyte)byteValue == -1; - bad = (sbyte)byteValue > 127; - bad = (sbyte)byteValue > (sbyte)127; + bad = (sbyte)byteValue > 127; // $ Alert + bad = (sbyte)byteValue > (sbyte)127; // $ Alert good = (int)uintValue == -1; good = (sbyte)uintValue == -1; - bad = (sbyte)uintValue == 256; + bad = (sbyte)uintValue == 256; // $ Alert System.Diagnostics.Debug.Assert(ulongValue >= ulong.MinValue); // GOOD } diff --git a/csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantCondition.expected b/csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantCondition.expected index 7d1d716386c..edf1f87232e 100644 --- a/csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantCondition.expected +++ b/csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantCondition.expected @@ -1,3 +1,29 @@ +| ConstantComparison.cs:19:15:19:27 | ... < ... | Condition always evaluates to 'false'. | ConstantComparison.cs:19:15:19:27 | ... < ... | dummy | +| ConstantComparison.cs:20:15:20:27 | ... > ... | Condition always evaluates to 'false'. | ConstantComparison.cs:20:15:20:27 | ... > ... | dummy | +| ConstantComparison.cs:21:15:21:28 | ... <= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:21:15:21:28 | ... <= ... | dummy | +| ConstantComparison.cs:22:15:22:28 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:22:15:22:28 | ... >= ... | dummy | +| ConstantComparison.cs:24:15:24:29 | ... == ... | Condition always evaluates to 'false'. | ConstantComparison.cs:24:15:24:29 | ... == ... | dummy | +| ConstantComparison.cs:25:15:25:29 | ... != ... | Condition always evaluates to 'true'. | ConstantComparison.cs:25:15:25:29 | ... != ... | dummy | +| ConstantComparison.cs:26:15:26:30 | ... == ... | Condition always evaluates to 'false'. | ConstantComparison.cs:26:15:26:30 | ... == ... | dummy | +| ConstantComparison.cs:27:15:27:30 | ... != ... | Condition always evaluates to 'true'. | ConstantComparison.cs:27:15:27:30 | ... != ... | dummy | +| ConstantComparison.cs:28:15:28:20 | ... != ... | Condition always evaluates to 'true'. | ConstantComparison.cs:28:15:28:20 | ... != ... | dummy | +| ConstantComparison.cs:42:15:42:32 | ... <= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:42:15:42:32 | ... <= ... | dummy | +| ConstantComparison.cs:43:15:43:28 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:43:15:43:28 | ... >= ... | dummy | +| ConstantComparison.cs:48:15:48:40 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:48:15:48:40 | ... >= ... | dummy | +| ConstantComparison.cs:49:15:49:40 | ... <= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:49:15:49:40 | ... <= ... | dummy | +| ConstantComparison.cs:54:15:54:42 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:54:15:54:42 | ... >= ... | dummy | +| ConstantComparison.cs:55:15:55:42 | ... <= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:55:15:55:42 | ... <= ... | dummy | +| ConstantComparison.cs:60:15:60:42 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:60:15:60:42 | ... >= ... | dummy | +| ConstantComparison.cs:61:15:61:42 | ... <= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:61:15:61:42 | ... <= ... | dummy | +| ConstantComparison.cs:66:15:66:44 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:66:15:66:44 | ... >= ... | dummy | +| ConstantComparison.cs:67:15:67:44 | ... <= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:67:15:67:44 | ... <= ... | dummy | +| ConstantComparison.cs:72:15:72:38 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:72:15:72:38 | ... >= ... | dummy | +| ConstantComparison.cs:73:15:73:38 | ... <= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:73:15:73:38 | ... <= ... | dummy | +| ConstantComparison.cs:78:15:78:40 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:78:15:78:40 | ... >= ... | dummy | +| ConstantComparison.cs:81:15:81:42 | ... >= ... | Condition always evaluates to 'true'. | ConstantComparison.cs:81:15:81:42 | ... >= ... | dummy | +| ConstantComparison.cs:88:15:88:36 | ... > ... | Condition always evaluates to 'false'. | ConstantComparison.cs:88:15:88:36 | ... > ... | dummy | +| ConstantComparison.cs:89:15:89:43 | ... > ... | Condition always evaluates to 'false'. | ConstantComparison.cs:89:15:89:43 | ... > ... | dummy | +| ConstantComparison.cs:92:15:92:37 | ... == ... | Condition always evaluates to 'false'. | ConstantComparison.cs:92:15:92:37 | ... == ... | dummy | | ConstantCondition.cs:38:18:38:29 | (...) ... | Expression is always 'null'. | ConstantCondition.cs:38:18:38:29 | (...) ... | dummy | | ConstantCondition.cs:39:18:39:24 | (...) ... | Expression is never 'null'. | ConstantCondition.cs:39:18:39:24 | (...) ... | dummy | | ConstantCondition.cs:46:17:46:26 | (...) ... | Expression is always 'null'. | ConstantCondition.cs:46:17:46:26 | (...) ... | dummy | diff --git a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.expected b/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.expected deleted file mode 100644 index 53f55501895..00000000000 --- a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.expected +++ /dev/null @@ -1,26 +0,0 @@ -| ConstantComparison.cs:19:15:19:27 | ... < ... | This comparison is always false. | -| ConstantComparison.cs:20:15:20:27 | ... > ... | This comparison is always false. | -| ConstantComparison.cs:21:15:21:28 | ... <= ... | This comparison is always true. | -| ConstantComparison.cs:22:15:22:28 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:24:15:24:29 | ... == ... | This comparison is always false. | -| ConstantComparison.cs:25:15:25:29 | ... != ... | This comparison is always true. | -| ConstantComparison.cs:26:15:26:30 | ... == ... | This comparison is always false. | -| ConstantComparison.cs:27:15:27:30 | ... != ... | This comparison is always true. | -| ConstantComparison.cs:28:15:28:20 | ... != ... | This comparison is always true. | -| ConstantComparison.cs:42:15:42:32 | ... <= ... | This comparison is always true. | -| ConstantComparison.cs:43:15:43:28 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:48:15:48:40 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:49:15:49:40 | ... <= ... | This comparison is always true. | -| ConstantComparison.cs:54:15:54:42 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:55:15:55:42 | ... <= ... | This comparison is always true. | -| ConstantComparison.cs:60:15:60:42 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:61:15:61:42 | ... <= ... | This comparison is always true. | -| ConstantComparison.cs:66:15:66:44 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:67:15:67:44 | ... <= ... | This comparison is always true. | -| ConstantComparison.cs:72:15:72:38 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:73:15:73:38 | ... <= ... | This comparison is always true. | -| ConstantComparison.cs:78:15:78:40 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:81:15:81:42 | ... >= ... | This comparison is always true. | -| ConstantComparison.cs:88:15:88:36 | ... > ... | This comparison is always false. | -| ConstantComparison.cs:89:15:89:43 | ... > ... | This comparison is always false. | -| ConstantComparison.cs:92:15:92:37 | ... == ... | This comparison is always false. | diff --git a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.qlref b/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.qlref deleted file mode 100644 index 8566e49f6cc..00000000000 --- a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/ConstantComparison.qlref +++ /dev/null @@ -1 +0,0 @@ -Likely Bugs/ConstantComparison.ql \ No newline at end of file diff --git a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/options b/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/options deleted file mode 100644 index 75c39b4541b..00000000000 --- a/csharp/ql/test/query-tests/Likely Bugs/ConstantComparison/options +++ /dev/null @@ -1,2 +0,0 @@ -semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj