Skip to content

Commit a25acd0

Browse files
authored
Merge pull request #1441 from calumgrant/cs/nullable-warning-expressions
C#: Extract SuppressNullableWarning expressions
2 parents 7790ac4 + b9d2fc3 commit a25acd0

File tree

13 files changed

+3870
-1
lines changed

13 files changed

+3870
-1
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ internal static Expression Create(ExpressionNodeInfo info)
242242
case SyntaxKind.SwitchExpression:
243243
return Switch.Create(info);
244244

245+
case SyntaxKind.SuppressNullableWarningExpression:
246+
return PostfixUnary.Create(info.SetKind(ExprKind.SUPPRESS_NULLABLE_WARNING), ((PostfixUnaryExpressionSyntax)info.Node).Operand);
247+
245248
default:
246249
info.Context.ModelError(info.Node, $"Unhandled expression '{info.Node}' of kind '{info.Node.Kind()}'");
247250
return new Unknown(info);

csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ public enum ExprKind
113113
PROPERTY_PATTERN = 116,
114114
POSITIONAL_PATTERN = 117,
115115
SWITCH_CASE = 118,
116-
ASSIGN_COALESCE = 119
116+
ASSIGN_COALESCE = 119,
117+
SUPPRESS_NULLABLE_WARNING = 120
117118
}
118119
}

csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,8 @@ module Internal {
673673
or
674674
e.(Call).getTarget().getSourceDeclaration() instanceof NonNullCallable and
675675
not e.(QualifiableExpr).isConditional()
676+
or
677+
e instanceof SuppressNullableWarningExpr
676678
}
677679

678680
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ module LocalFlow {
8383
scope = e2 and
8484
isSuccessor = true
8585
or
86+
e1 = e2.(SuppressNullableWarningExpr).getExpr() and
87+
scope = e2 and
88+
isSuccessor = true
89+
or
8690
e2 = any(ConditionalExpr ce |
8791
e1 = ce.getThen() or
8892
e1 = ce.getElse()

csharp/ql/src/semmle/code/csharp/exprs/Expr.qll

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,3 +990,20 @@ class IndexExpr extends Expr, @index_expr {
990990

991991
override string toString() { result = "^..." }
992992
}
993+
994+
/**
995+
* A nullable warning suppression expression, for example `x!` in
996+
* ```
997+
* string GetName()
998+
* {
999+
* string? x = ...;
1000+
* return x!;
1001+
* }
1002+
* ```
1003+
*/
1004+
class SuppressNullableWarningExpr extends Expr, @suppress_nullable_warning_expr {
1005+
/** Gets the expression, for example `x` in `x!`. */
1006+
Expr getExpr() { result.getParent() = this }
1007+
1008+
override string toString() { result = "...!" }
1009+
}

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,7 @@ case @expr.kind of
987987
| 117 = @positional_pattern_expr
988988
| 118 = @switch_case_expr
989989
| 119 = @assign_coalesce_expr
990+
| 120 = @suppress_nullable_warning_expr
990991
;
991992

992993
@switch = @switch_stmt | @switch_expr;

csharp/ql/src/semmlecode.csharp.dbscheme.stats

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,10 @@
836836
<v>0</v>
837837
</e>
838838
<e>
839+
<k>@suppress_nullable_warning_expr</k>
840+
<v>500</v>
841+
</e>
842+
<e>
839843
<k>@xmldtd</k>
840844
<v>2</v>
841845
</e>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
class NullableRefTypes
4+
{
5+
void TestNullableRefTypes()
6+
{
7+
string? x = "source";
8+
string y = x!;
9+
y = x!!;
10+
x = null;
11+
y = x!;
12+
}
13+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
suppressNullableWarnings
2+
| NullableRefTypes.cs:8:20:8:21 | ...! | NullableRefTypes.cs:8:20:8:20 | access to local variable x |
3+
| NullableRefTypes.cs:9:13:9:14 | ...! | NullableRefTypes.cs:9:13:9:13 | access to local variable x |
4+
| NullableRefTypes.cs:9:13:9:15 | ...! | NullableRefTypes.cs:9:13:9:14 | ...! |
5+
| NullableRefTypes.cs:11:13:11:14 | ...! | NullableRefTypes.cs:11:13:11:13 | access to local variable x |
6+
nullableDataFlow
7+
| NullableRefTypes.cs:7:17:7:28 | SSA def(x) | NullableRefTypes.cs:8:20:8:20 | access to local variable x |
8+
| NullableRefTypes.cs:7:21:7:28 | "source" | NullableRefTypes.cs:7:17:7:28 | SSA def(x) |
9+
| NullableRefTypes.cs:8:20:8:20 | access to local variable x | NullableRefTypes.cs:8:20:8:21 | ...! |
10+
| NullableRefTypes.cs:8:20:8:20 | access to local variable x | NullableRefTypes.cs:9:13:9:13 | access to local variable x |
11+
| NullableRefTypes.cs:9:13:9:13 | access to local variable x | NullableRefTypes.cs:9:13:9:14 | ...! |
12+
| NullableRefTypes.cs:9:13:9:14 | ...! | NullableRefTypes.cs:9:13:9:15 | ...! |
13+
| NullableRefTypes.cs:10:9:10:16 | SSA def(x) | NullableRefTypes.cs:11:13:11:13 | access to local variable x |
14+
| NullableRefTypes.cs:10:13:10:16 | null | NullableRefTypes.cs:10:9:10:16 | SSA def(x) |
15+
| NullableRefTypes.cs:11:13:11:13 | access to local variable x | NullableRefTypes.cs:11:13:11:14 | ...! |
16+
nullableControlFlow
17+
| NullableRefTypes.cs:5:10:5:29 | enter TestNullableRefTypes | NullableRefTypes.cs:6:5:12:5 | {...} | successor |
18+
| NullableRefTypes.cs:6:5:12:5 | {...} | NullableRefTypes.cs:7:9:7:29 | ... ...; | successor |
19+
| NullableRefTypes.cs:7:9:7:29 | ... ...; | NullableRefTypes.cs:7:21:7:28 | "source" | successor |
20+
| NullableRefTypes.cs:7:17:7:28 | String x = ... | NullableRefTypes.cs:8:9:8:22 | ... ...; | successor |
21+
| NullableRefTypes.cs:7:21:7:28 | "source" | NullableRefTypes.cs:7:17:7:28 | String x = ... | successor |
22+
| NullableRefTypes.cs:8:9:8:22 | ... ...; | NullableRefTypes.cs:8:20:8:20 | access to local variable x | successor |
23+
| NullableRefTypes.cs:8:16:8:21 | String y = ... | NullableRefTypes.cs:9:9:9:16 | ...; | successor |
24+
| NullableRefTypes.cs:8:20:8:20 | access to local variable x | NullableRefTypes.cs:8:20:8:21 | ...! | successor |
25+
| NullableRefTypes.cs:8:20:8:21 | ...! | NullableRefTypes.cs:8:16:8:21 | String y = ... | successor |
26+
| NullableRefTypes.cs:9:9:9:15 | ... = ... | NullableRefTypes.cs:10:9:10:17 | ...; | successor |
27+
| NullableRefTypes.cs:9:9:9:16 | ...; | NullableRefTypes.cs:9:13:9:13 | access to local variable x | successor |
28+
| NullableRefTypes.cs:9:13:9:13 | access to local variable x | NullableRefTypes.cs:9:13:9:14 | ...! | successor |
29+
| NullableRefTypes.cs:9:13:9:14 | ...! | NullableRefTypes.cs:9:13:9:15 | ...! | successor |
30+
| NullableRefTypes.cs:9:13:9:15 | ...! | NullableRefTypes.cs:9:9:9:15 | ... = ... | successor |
31+
| NullableRefTypes.cs:10:9:10:16 | ... = ... | NullableRefTypes.cs:11:9:11:15 | ...; | successor |
32+
| NullableRefTypes.cs:10:9:10:17 | ...; | NullableRefTypes.cs:10:13:10:16 | null | successor |
33+
| NullableRefTypes.cs:10:13:10:16 | null | NullableRefTypes.cs:10:9:10:16 | ... = ... | successor |
34+
| NullableRefTypes.cs:11:9:11:14 | ... = ... | NullableRefTypes.cs:5:10:5:29 | exit TestNullableRefTypes | successor |
35+
| NullableRefTypes.cs:11:9:11:15 | ...; | NullableRefTypes.cs:11:13:11:13 | access to local variable x | successor |
36+
| NullableRefTypes.cs:11:13:11:13 | access to local variable x | NullableRefTypes.cs:11:13:11:14 | ...! | successor |
37+
| NullableRefTypes.cs:11:13:11:14 | ...! | NullableRefTypes.cs:11:9:11:14 | ... = ... | successor |
38+
nonNullExpressions
39+
| NullableRefTypes.cs:7:21:7:28 | "source" |
40+
| NullableRefTypes.cs:8:20:8:20 | access to local variable x |
41+
| NullableRefTypes.cs:8:20:8:21 | ...! |
42+
| NullableRefTypes.cs:9:9:9:15 | ... = ... |
43+
| NullableRefTypes.cs:9:13:9:13 | access to local variable x |
44+
| NullableRefTypes.cs:9:13:9:14 | ...! |
45+
| NullableRefTypes.cs:9:13:9:15 | ...! |
46+
| NullableRefTypes.cs:11:9:11:14 | ... = ... |
47+
| NullableRefTypes.cs:11:13:11:14 | ...! |
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import csharp
2+
import semmle.code.csharp.dataflow.Nullness
3+
4+
query predicate suppressNullableWarnings(SuppressNullableWarningExpr e, Expr op) {
5+
op = e.getExpr()
6+
}
7+
8+
query predicate nullableDataFlow(DataFlow::Node src, DataFlow::Node sink) {
9+
src.getEnclosingCallable().hasName("TestNullableRefTypes") and
10+
DataFlow::localFlowStep(src, sink)
11+
}
12+
13+
query predicate nullableControlFlow(
14+
ControlFlow::Node a, ControlFlow::Node b, ControlFlow::SuccessorType t
15+
) {
16+
a.getEnclosingCallable().hasName("TestNullableRefTypes") and
17+
b = a.getASuccessorByType(t)
18+
}
19+
20+
query predicate nonNullExpressions(NonNullExpr e) {
21+
e.getEnclosingCallable().getName() = "TestNullableRefTypes"
22+
}

0 commit comments

Comments
 (0)