Skip to content

Commit 741380e

Browse files
committed
C#: Handle discard variable declarations in switch expressions
1 parent 102490a commit 741380e

12 files changed

Lines changed: 79 additions & 55 deletions

File tree

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,20 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE
1818
case DeclarationPatternSyntax declPattern:
1919
// Creates a single local variable declaration.
2020
{
21-
if (declPattern.Designation is VariableDesignationSyntax designation && cx.Model(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
21+
if (declPattern.Designation is VariableDesignationSyntax designation)
2222
{
23-
var type = Type.Create(cx, symbol.Type);
24-
25-
return VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, parent, child);
23+
if (cx.Model(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
24+
{
25+
var type = Type.Create(cx, symbol.Type);
26+
return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, parent, child);
27+
}
28+
if (designation is DiscardDesignationSyntax)
29+
{
30+
return Expressions.TypeAccess.Create(cx, declPattern.Type, parent, child);
31+
}
32+
throw new InternalError(designation, "Designation pattern not handled");
2633
}
27-
throw new InternalError(syntax, "Is pattern not handled");
34+
throw new InternalError(declPattern, "Declaration pattern not handled");
2835
}
2936

3037
case RecursivePatternSyntax recPattern:
@@ -40,7 +47,7 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE
4047
{
4148
var type = Type.Create(cx, symbol.Type);
4249

43-
return VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(varDesignation.GetLocation()), false, parent, child);
50+
return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), cx.Create(varDesignation.GetLocation()), false, parent, child);
4451
}
4552
else
4653
{
@@ -54,7 +61,7 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE
5461
return new Discard(cx, dp, parent, child);
5562

5663
default:
57-
throw new InternalError(syntax, "Is pattern not handled");
64+
throw new InternalError(syntax, "Pattern not handled");
5865
}
5966
}
6067
}
@@ -108,7 +115,7 @@ public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionPa
108115
{
109116
var type = Type.Create(cx, symbol.Type);
110117

111-
VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, this, 0);
118+
VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, this, 0);
112119
}
113120

114121
if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc)
@@ -135,7 +142,7 @@ private void PopulatePattern(PatternSyntax pattern, TypeSyntax optionalType, Syn
135142
if (!(designation is null) && cx.Model(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
136143
{
137144
var type = Type.Create(cx, symbol.Type);
138-
VariableDeclaration.Create(cx, symbol, type, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 2);
145+
VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 1);
139146
}
140147
else if (!isVar)
141148
Expressions.TypeAccess.Create(cx, optionalType, this, 1);

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,21 @@ protected Expression DeclareRangeVariable(Context cx, IExpressionParentEntity pa
6666
Extraction.Entities.Location nameLoc;
6767

6868
Type declType;
69+
TypeSyntax declTypeSyntax = null;
6970
if (getElement)
7071
{
7172
var from = node as FromClauseSyntax;
72-
declType = from != null && from.Type != null
73-
? Type.Create(cx, cx.GetType(from.Type))
74-
: type.ElementType;
73+
(declType, declTypeSyntax) = from != null && from.Type != null
74+
? (Type.Create(cx, cx.GetType(from.Type)), from.Type)
75+
: (type.ElementType, null);
7576
}
7677
else
7778
declType = type;
7879

7980
var decl = VariableDeclaration.Create(cx,
8081
variableSymbol,
8182
declType,
83+
declTypeSyntax,
8284
cx.Create(node.GetLocation()),
8385
nameLoc = cx.Create(name.GetLocation()),
8486
true,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ protected override void Populate()
1818
{
1919
SwitchedExpr = Expression.Create(cx, Syntax.GoverningExpression, this, -1);
2020
int child = 0;
21-
foreach(var arm in Syntax.Arms)
21+
foreach (var arm in Syntax.Arms)
2222
{
2323
new SwitchCase(cx, arm, this, child++);
2424
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ class VariableDeclaration : Expression
1111
{
1212
VariableDeclaration(IExpressionInfo info) : base(info) { }
1313

14-
public static VariableDeclaration Create(Context cx, ISymbol symbol, Type type, Extraction.Entities.Location exprLocation, Extraction.Entities.Location declLocation, bool isVar, IExpressionParentEntity parent, int child)
14+
public static VariableDeclaration Create(Context cx, ISymbol symbol, Type type, TypeSyntax mention, Extraction.Entities.Location exprLocation, Extraction.Entities.Location declLocation, bool isVar, IExpressionParentEntity parent, int child)
1515
{
1616
var ret = new VariableDeclaration(new ExpressionInfo(cx, type, exprLocation, ExprKind.LOCAL_VAR_DECL, parent, child, false, null));
17-
cx.Try(null, null, () => LocalVariable.Create(cx, symbol, ret, isVar, declLocation));
17+
cx.Try(null, null, () =>
18+
{
19+
LocalVariable.Create(cx, symbol, ret, isVar, declLocation);
20+
if (mention != null)
21+
TypeMention.Create(cx, mention, parent, type);
22+
});
1823
return ret;
1924
}
2025

@@ -65,7 +70,7 @@ public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPat
6570
{
6671
var child0 = 0;
6772
foreach (var variable in designation.Variables)
68-
switch(variable)
73+
switch (variable)
6974
{
7075
case ParenthesizedVariableDesignationSyntax paren:
7176
CreateParenthesized(cx, varPattern, paren, tuple, child0++);
@@ -97,7 +102,7 @@ public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPat
97102

98103
static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
99104
{
100-
switch(designation)
105+
switch (designation)
101106
{
102107
case SingleVariableDesignationSyntax single:
103108
return CreateSingle(cx, node, single, parent, child);

csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ private void PopulatePattern(PatternSyntax pattern, TypeSyntax optionalType, Var
7676
if (cx.Model(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
7777
{
7878
var type = Type.Create(cx, symbol.Type);
79-
Expressions.VariableDeclaration.Create(cx, symbol, type, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 0);
79+
Expressions.VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 0);
8080
}
8181
break;
8282
case DiscardDesignationSyntax discard:

csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ protected override void Populate()
2727
var location = cx.Create(Stmt.Identifier.GetLocation());
2828

2929
if (typeSymbol.Name != "_")
30-
Expressions.VariableDeclaration.Create(cx, typeSymbol, type, location, location, Stmt.Type.IsVar, this, 0);
31-
TypeMention.Create(cx, Stmt.Type, this, type);
30+
Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, location, Stmt.Type.IsVar, this, 0);
31+
else
32+
TypeMention.Create(cx, Stmt.Type, this, type);
3233

3334
Statement.Create(cx, Stmt.Statement, this, 2);
3435
}

csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,11 +1241,9 @@
12411241
| Switch.cs:46:17:46:17 | access to parameter o | Switch.cs:46:17:46:17 | access to parameter o |
12421242
| Switch.cs:48:13:48:23 | case ...: | Switch.cs:48:13:48:23 | case ...: |
12431243
| Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:48:18:48:20 | access to type Int32 |
1244-
| Switch.cs:48:22:48:22 | _ | Switch.cs:48:22:48:22 | _ |
12451244
| Switch.cs:49:17:49:22 | break; | Switch.cs:49:17:49:22 | break; |
12461245
| Switch.cs:50:13:50:39 | case ...: | Switch.cs:50:13:50:39 | case ...: |
12471246
| Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:18:50:21 | access to type Boolean |
1248-
| Switch.cs:50:23:50:23 | _ | Switch.cs:50:23:50:23 | _ |
12491247
| Switch.cs:50:30:50:30 | access to parameter o | Switch.cs:50:30:50:30 | access to parameter o |
12501248
| Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:30:50:30 | access to parameter o |
12511249
| Switch.cs:50:35:50:38 | null | Switch.cs:50:35:50:38 | null |
@@ -1267,7 +1265,6 @@
12671265
| Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:25:68:25 | access to parameter s |
12681266
| Switch.cs:70:13:70:24 | case ...: | Switch.cs:70:13:70:24 | case ...: |
12691267
| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:18:70:20 | access to type Int32 |
1270-
| Switch.cs:70:22:70:22 | _ | Switch.cs:70:22:70:22 | _ |
12711268
| Switch.cs:71:15:71:20 | break; | Switch.cs:71:15:71:20 | break; |
12721269
| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:13:72:21 | case ...: |
12731270
| Switch.cs:72:18:72:19 | "" | Switch.cs:72:18:72:19 | "" |
@@ -1295,7 +1292,6 @@
12951292
| Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:93:17:93:17 | access to parameter o |
12961293
| Switch.cs:95:13:95:24 | case ...: | Switch.cs:95:13:95:24 | case ...: |
12971294
| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 |
1298-
| Switch.cs:95:22:95:22 | _ | Switch.cs:95:22:95:22 | _ |
12991295
| Switch.cs:96:15:96:26 | return ...; | Switch.cs:96:22:96:25 | true |
13001296
| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true |
13011297
| Switch.cs:98:9:98:21 | return ...; | Switch.cs:98:16:98:20 | false |

csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,14 +1588,12 @@
15881588
| Switch.cs:48:13:48:23 | case ...: | Switch.cs:49:17:49:22 | break; | break |
15891589
| Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:48:18:48:20 | access to type Int32 | match |
15901590
| Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:48:18:48:20 | access to type Int32 | no-match |
1591-
| Switch.cs:48:22:48:22 | _ | Switch.cs:48:22:48:22 | _ | normal |
15921591
| Switch.cs:49:17:49:22 | break; | Switch.cs:49:17:49:22 | break; | break |
15931592
| Switch.cs:50:13:50:39 | case ...: | Switch.cs:50:18:50:21 | access to type Boolean | no-match |
15941593
| Switch.cs:50:13:50:39 | case ...: | Switch.cs:50:30:50:38 | ... != ... | false/false |
15951594
| Switch.cs:50:13:50:39 | case ...: | Switch.cs:51:17:51:22 | break; | break |
15961595
| Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:18:50:21 | access to type Boolean | match |
15971596
| Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:18:50:21 | access to type Boolean | no-match |
1598-
| Switch.cs:50:23:50:23 | _ | Switch.cs:50:23:50:23 | _ | normal |
15991597
| Switch.cs:50:30:50:30 | access to parameter o | Switch.cs:50:30:50:30 | access to parameter o | normal |
16001598
| Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:30:50:38 | ... != ... | false/false |
16011599
| Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:30:50:38 | ... != ... | true/true |
@@ -1626,7 +1624,6 @@
16261624
| Switch.cs:70:13:70:24 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | no-match |
16271625
| Switch.cs:70:13:70:24 | case ...: | Switch.cs:71:15:71:20 | break; | break |
16281626
| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:18:70:20 | access to type Int32 | no-match |
1629-
| Switch.cs:70:22:70:22 | _ | Switch.cs:70:22:70:22 | _ | normal |
16301627
| Switch.cs:71:15:71:20 | break; | Switch.cs:71:15:71:20 | break; | break |
16311628
| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:18:72:19 | "" | no-match |
16321629
| Switch.cs:72:13:72:21 | case ...: | Switch.cs:73:15:73:20 | break; | break |
@@ -1672,7 +1669,6 @@
16721669
| Switch.cs:95:13:95:24 | case ...: | Switch.cs:96:15:96:26 | return ...; | return |
16731670
| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 | match |
16741671
| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 | no-match |
1675-
| Switch.cs:95:22:95:22 | _ | Switch.cs:95:22:95:22 | _ | normal |
16761672
| Switch.cs:96:15:96:26 | return ...; | Switch.cs:96:15:96:26 | return ...; | return |
16771673
| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true | normal |
16781674
| Switch.cs:98:9:98:21 | return ...; | Switch.cs:98:9:98:21 | return ...; | return |

csharp/ql/test/library-tests/csharp7/Discards.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@
66
| CSharp7.cs:224:17:224:17 | _ | Double |
77
| CSharp7.cs:224:28:224:28 | _ | Boolean |
88
| CSharp7.cs:225:10:225:10 | _ | Int32 |
9-
| CSharp7.cs:267:25:267:25 | _ | null |

csharp/ql/test/library-tests/csharp8/patterns.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ void Expressions2(object o)
137137
{
138138
1 => throw new ArgumentException(),
139139
2 => 3,
140-
object y when y is {} => 4
140+
object y when y is {} => 4,
141+
string _ => 5,
142+
MyStruct { X: 10 } _ => 6
141143
};
142144
}
143145
catch(InvalidOperationException ex)

0 commit comments

Comments
 (0)