Skip to content

Commit b775eb4

Browse files
authored
Merge pull request #4789 from tamasvajk/feature/csharp9-relational-pattern2
C#: Relational patterns
2 parents 25095f9 + 8400a38 commit b775eb4

File tree

16 files changed

+6715
-2705
lines changed

16 files changed

+6715
-2705
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
lgtm,codescanning
2+
* The `RelationalPatternExpr` and its 4 sub class have been added to support C# 9
3+
relational `<`, `>`, `<=`, and `>=` patterns.

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ internal static Expression Create(Context cx, PatternSyntax syntax, IExpressionP
4545
case RecursivePatternSyntax recPattern:
4646
return new RecursivePattern(cx, recPattern, parent, child);
4747

48+
case RelationalPatternSyntax relPattern:
49+
return new RelationalPattern(cx, relPattern, parent, child);
50+
4851
case VarPatternSyntax varPattern:
4952
switch (varPattern.Designation)
5053
{

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ internal class RecursivePattern : Expression
1515
/// <param name="syntax">The syntax node of the recursive pattern.</param>
1616
/// <param name="parent">The parent pattern/expression.</param>
1717
/// <param name="child">The child index of this pattern.</param>
18-
/// <param name="isTopLevel">If this pattern is in the top level of a case/is. In that case, the variable and type access are populated elsewhere.</param>
1918
public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionParentEntity parent, int child) :
2019
base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null))
2120
{
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
using Microsoft.CodeAnalysis.CSharp;
4+
using Semmle.Extraction.Kinds;
5+
using Semmle.Extraction.Entities;
6+
7+
namespace Semmle.Extraction.CSharp.Entities.Expressions
8+
{
9+
internal class RelationalPattern : Expression
10+
{
11+
public RelationalPattern(Context cx, RelationalPatternSyntax syntax, IExpressionParentEntity parent, int child) :
12+
base(new ExpressionInfo(cx, NullType.Create(cx), cx.Create(syntax.GetLocation()), GetKind(syntax.OperatorToken), parent, child, false, null))
13+
{
14+
Expression.Create(cx, syntax.Expression, this, 0);
15+
}
16+
17+
private static ExprKind GetKind(SyntaxToken operatorToken)
18+
{
19+
return operatorToken.Kind() switch
20+
{
21+
SyntaxKind.LessThanEqualsToken => ExprKind.LE_PATTERN,
22+
SyntaxKind.GreaterThanEqualsToken => ExprKind.GE_PATTERN,
23+
SyntaxKind.LessThanToken => ExprKind.LT_PATTERN,
24+
SyntaxKind.GreaterThanToken => ExprKind.GT_PATTERN,
25+
_ => throw new InternalError(operatorToken.Parent, $"Relation pattern with operator token '{operatorToken.Kind()}' is not supported."),
26+
};
27+
}
28+
}
29+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ public enum ExprKind
116116
ASSIGN_COALESCE = 119,
117117
SUPPRESS_NULLABLE_WARNING = 120,
118118
NAMESPACE_ACCESS = 121,
119+
LT_PATTERN = 122,
120+
GT_PATTERN = 123,
121+
LE_PATTERN = 124,
122+
GE_PATTERN = 125,
119123
NOT_PATTERN = 126
120124
}
121125
}

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,45 @@ class ConstantPatternExpr extends PatternExpr {
345345
override string getAPrimaryQlClass() { result = "ConstantPatternExpr" }
346346
}
347347

348+
/** A relational pattern, for example `>1` in `x is >1`. */
349+
class RelationalPatternExpr extends PatternExpr, @relational_pattern_expr {
350+
/** Gets the name of the operator in this pattern. */
351+
string getOperator() { none() }
352+
353+
/** Gets the expression of this relational pattern. */
354+
Expr getExpr() { result = this.getChild(0) }
355+
356+
override string toString() { result = getOperator() + " ..." }
357+
}
358+
359+
/** A less-than pattern, for example `< 10` in `x is < 10`. */
360+
class LTPattern extends RelationalPatternExpr, @lt_pattern_expr {
361+
override string getOperator() { result = "<" }
362+
363+
override string getAPrimaryQlClass() { result = "LTPattern" }
364+
}
365+
366+
/** A greater-than pattern, for example `> 10` in `x is > 10`. */
367+
class GTPattern extends RelationalPatternExpr, @gt_pattern_expr {
368+
override string getOperator() { result = ">" }
369+
370+
override string getAPrimaryQlClass() { result = "GTPattern" }
371+
}
372+
373+
/** A less-than or equals pattern, for example `<= 10` in `x is <= 10`. */
374+
class LEPattern extends RelationalPatternExpr, @le_pattern_expr {
375+
override string getOperator() { result = "<=" }
376+
377+
override string getAPrimaryQlClass() { result = "LEPattern" }
378+
}
379+
380+
/** A greater-than or equals pattern, for example `>= 10` in `x is >= 10` */
381+
class GEPattern extends RelationalPatternExpr, @ge_pattern_expr {
382+
override string getOperator() { result = ">=" }
383+
384+
override string getAPrimaryQlClass() { result = "GEPattern" }
385+
}
386+
348387
/**
349388
* A type pattern, for example `string` in `x is string`, `string s` in
350389
* `x is string s`, or `string _` in `x is string _`.

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,13 +1010,18 @@ case @expr.kind of
10101010
| 120 = @suppress_nullable_warning_expr
10111011
| 121 = @namespace_access_expr
10121012
/* C# 9.0 */
1013+
| 122 = @lt_pattern_expr
1014+
| 123 = @gt_pattern_expr
1015+
| 124 = @le_pattern_expr
1016+
| 125 = @ge_pattern_expr
10131017
| 126 = @not_pattern_expr
10141018
;
10151019

10161020
@switch = @switch_stmt | @switch_expr;
10171021
@case = @case_stmt | @switch_case_expr;
10181022
@pattern_match = @case | @is_expr;
10191023
@unary_pattern_expr = @not_pattern_expr;
1024+
@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
10201025

10211026
@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
10221027
@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;

0 commit comments

Comments
 (0)