Skip to content

Commit e79cb44

Browse files
authored
Merge pull request #18976 from michaelnebel/csharp/constant-condition
C#: Increase precision of `cs/constant-condition`.
2 parents 86bd3b8 + 42f86a8 commit e79cb44

12 files changed

+99
-62
lines changed

csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,14 @@ class ConstantMatchingCondition extends ConstantCondition {
119119
}
120120

121121
override predicate isWhiteListed() {
122-
exists(SwitchExpr se, int i |
123-
se.getCase(i).getPattern() = this.(DiscardExpr) and
122+
exists(Switch se, Case c, int i |
123+
c = se.getCase(i) and
124+
c.getPattern() = this.(DiscardExpr)
125+
|
124126
i > 0
127+
or
128+
i = 0 and
129+
exists(Expr cond | c.getCondition() = cond and not isConstantCondition(cond, true))
125130
)
126131
or
127132
this = any(PositionalPatternExpr ppe).getPattern(_)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Increase query precision for `cs/constant-condition` and allow the use of discards in switch/case statements and also take the condition (if any) into account.

csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantCondition.cs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,18 @@ class ConstantNullness
3535
{
3636
void M1(int i)
3737
{
38-
var j = ((string)null)?.Length; // BAD
39-
var s = ((int?)i)?.ToString(); // BAD
38+
var j = ((string)null)?.Length; // $ Alert
39+
var s = ((int?)i)?.ToString(); // $ Alert
4040
var k = s?.Length; // GOOD
4141
k = s?.ToLower()?.Length; // GOOD
4242
}
4343

4444
void M2(int i)
4545
{
46-
var j = (int?)null ?? 0; // BAD
47-
var s = "" ?? "a"; // BAD
48-
j = (int?)i ?? 1; // BAD
49-
s = ""?.CommaJoinWith(s); // BAD
46+
var j = (int?)null ?? 0; // $ Alert
47+
var s = "" ?? "a"; // $ Alert
48+
j = (int?)i ?? 1; // $ Alert
49+
s = ""?.CommaJoinWith(s); // $ Alert
5050
s = s ?? ""; // GOOD
5151
s = (i == 0 ? s : null) ?? s; // GOOD
5252
var k = (i == 0 ? s : null)?.Length; // GOOD
@@ -59,9 +59,9 @@ void M1()
5959
{
6060
switch (1 + 2)
6161
{
62-
case 2: // BAD
62+
case 2: // $ Alert
6363
break;
64-
case 3: // BAD
64+
case 3: // $ Alert
6565
break;
6666
case int _: // GOOD
6767
break;
@@ -72,7 +72,7 @@ void M2(string s)
7272
{
7373
switch ((object)s)
7474
{
75-
case int _: // BAD
75+
case int _: // $ Alert
7676
break;
7777
case "": // GOOD
7878
break;
@@ -92,7 +92,7 @@ string M4(object o)
9292
{
9393
return o switch
9494
{
95-
_ => o.ToString() // BAD
95+
_ => o.ToString() // $ Alert
9696
};
9797
}
9898

@@ -111,7 +111,7 @@ void M6(bool b1, bool b2)
111111
return;
112112
if (!b2)
113113
return;
114-
if (b1 && b2) // BAD
114+
if (b1 && b2) // $ Alert
115115
return;
116116
}
117117

@@ -124,6 +124,35 @@ string M7(object o)
124124
_ => "" // GOOD
125125
};
126126
}
127+
128+
string M8(int i)
129+
{
130+
return i switch
131+
{
132+
_ when i % 2 == 0 => "even", // GOOD
133+
_ => "odd" // GOOD
134+
};
135+
}
136+
137+
string M9(int i)
138+
{
139+
switch (i)
140+
{
141+
case var _: // $ Alert
142+
return "even";
143+
}
144+
}
145+
146+
string M10(int i)
147+
{
148+
switch (i)
149+
{
150+
case var _ when i % 2 == 0: // GOOD
151+
return "even";
152+
case var _: // GOOD
153+
return "odd";
154+
}
155+
}
127156
}
128157

129158
class Assertions

csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantCondition.expected

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
| ConstantCondition.cs:95:13:95:13 | _ | Pattern always matches. |
1111
| ConstantCondition.cs:114:13:114:14 | access to parameter b1 | Condition always evaluates to 'true'. |
1212
| ConstantCondition.cs:114:19:114:20 | access to parameter b2 | Condition always evaluates to 'true'. |
13-
| ConstantConditionBad.cs:5:16:5:20 | ... > ... | Condition always evaluates to 'false'. |
13+
| ConstantCondition.cs:141:22:141:22 | _ | Pattern always matches. |
1414
| ConstantConditionalExpressionCondition.cs:11:22:11:34 | ... == ... | Condition always evaluates to 'true'. |
1515
| ConstantConditionalExpressionCondition.cs:12:21:12:25 | false | Condition always evaluates to 'false'. |
1616
| ConstantConditionalExpressionCondition.cs:13:21:13:30 | ... == ... | Condition always evaluates to 'true'. |
@@ -19,6 +19,7 @@
1919
| ConstantIfCondition.cs:11:17:11:29 | ... == ... | Condition always evaluates to 'true'. |
2020
| ConstantIfCondition.cs:14:17:14:21 | false | Condition always evaluates to 'false'. |
2121
| ConstantIfCondition.cs:17:17:17:26 | ... == ... | Condition always evaluates to 'true'. |
22+
| ConstantIfCondition.cs:30:20:30:24 | ... > ... | Condition always evaluates to 'false'. |
2223
| ConstantIsNullOrEmpty.cs:10:21:10:54 | call to method IsNullOrEmpty | Condition always evaluates to 'false'. |
2324
| ConstantIsNullOrEmpty.cs:46:21:46:46 | call to method IsNullOrEmpty | Condition always evaluates to 'true'. |
2425
| ConstantIsNullOrEmpty.cs:50:21:50:44 | call to method IsNullOrEmpty | Condition always evaluates to 'true'. |
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
Bad Practices/Control-Flow/ConstantCondition.ql
1+
query: Bad Practices/Control-Flow/ConstantCondition.ql
2+
postprocess: utils/test/InlineExpectationsTestQuery.ql

csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantConditionBad.cs

Lines changed: 0 additions & 7 deletions
This file was deleted.

csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantConditionalExpressionCondition.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ class Main
88

99
public void Foo()
1010
{
11-
int i = (ZERO == 1 - 1) ? 0 : 1; // BAD
12-
int j = false ? 0 : 1; // BAD
13-
int k = " " == " " ? 0 : 1; // BAD
14-
int l = (" "[0] == ' ') ? 0 : 1; // BAD: but not flagged
11+
int i = (ZERO == 1 - 1) ? 0 : 1; // $ Alert
12+
int j = false ? 0 : 1; // $ Alert
13+
int k = " " == " " ? 0 : 1; // $ Alert
14+
int l = (" "[0] == ' ') ? 0 : 1; // Missing Alert
1515
int m = Bar() == 0 ? 0 : 1; // GOOD
1616
}
1717

@@ -21,5 +21,4 @@ public int Bar()
2121
}
2222

2323
}
24-
2524
}

csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantForCondition.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ class Main
66
{
77
public void M()
88
{
9-
for (int i = 0; false; i++) // GOOD
9+
for (int i = 0; false; i++) // $ Alert
1010
;
11-
for (int i = 0; 0 == 1; i++) // BAD
11+
for (int i = 0; 0 == 1; i++) // $ Alert
1212
;
1313
for (; ; ) // GOOD
1414
;

csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantIfCondition.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,28 @@ class Main
88

99
public void Foo()
1010
{
11-
if (ZERO == 1 - 1)
12-
{ // BAD
11+
if (ZERO == 1 - 1) // $ Alert
12+
{
1313
}
14-
if (false)
15-
{ // BAD
14+
if (false) // $ Alert
15+
{
1616
}
17-
if (" " == " ")
18-
{ // BAD
17+
if (" " == " ") // $ Alert
18+
{
1919
}
20-
if (" "[0] == ' ')
21-
{ // BAD: but not flagged
20+
if (" "[0] == ' ') // Missing Alert
21+
{
2222
}
23-
if (Bar() == 0)
24-
{ // GOOD
23+
if (Bar() == 0) // GOOD
24+
{
2525
}
2626
}
2727

28+
public int Max(int a, int b)
29+
{
30+
return a > a ? a : b; // $ Alert
31+
}
32+
2833
public int Bar()
2934
{
3035
return ZERO;

csharp/ql/test/query-tests/Bad Practices/Control-Flow/ConstantCondition/ConstantIsNullOrEmpty.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ internal class Program
77
static void Main(string[] args)
88
{
99
{
10-
if (string.IsNullOrEmpty(nameof(args))) // bad: always false
10+
if (string.IsNullOrEmpty(nameof(args))) // $ Alert
1111
{
1212
}
1313

1414
string? x = null;
15-
if (string.IsNullOrEmpty(x)) // would be nice... bad: always true
15+
if (string.IsNullOrEmpty(x)) // Missing Alert (always true)
1616
{
1717
}
1818

1919
string y = "";
20-
if (string.IsNullOrEmpty(y)) // would be nice... bad: always true
20+
if (string.IsNullOrEmpty(y)) // Missing Alert (always true)
2121
{
2222
}
2323

@@ -28,12 +28,12 @@ static void Main(string[] args)
2828
}
2929

3030
string z = " ";
31-
if (string.IsNullOrEmpty(z)) // would be nice... bad: always false
31+
if (string.IsNullOrEmpty(z)) // Missing Alert (always false)
3232
{
3333
}
3434

3535
string a = "a";
36-
if (string.IsNullOrEmpty(a)) // would be nice... bad: always false
36+
if (string.IsNullOrEmpty(a)) // Missing Alert (always false)
3737
{
3838
}
3939

@@ -43,18 +43,18 @@ static void Main(string[] args)
4343
{
4444
}
4545

46-
if (string.IsNullOrEmpty(null)) // bad: always true
46+
if (string.IsNullOrEmpty(null)) // $ Alert
4747
{
4848
}
4949

50-
if (string.IsNullOrEmpty("")) // bad: always true
50+
if (string.IsNullOrEmpty("")) // $ Alert
5151
{
5252
}
5353

54-
if (string.IsNullOrEmpty(" ")) // bad: always false
54+
if (string.IsNullOrEmpty(" ")) // $ Alert
5555
{
5656
}
5757
}
5858
}
5959
}
60-
}
60+
}

0 commit comments

Comments
 (0)