Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4685fc0

Browse files
committed
C#: Extract binary patterns
1 parent 39977e9 commit 4685fc0

12 files changed

Lines changed: 164 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
lgtm,codescanning
2+
* The `BinaryPatternExpr` class has been added to support C# 9 `and` and `or`
3+
patterns.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using Semmle.Extraction.Entities;
5+
using Semmle.Extraction.Kinds;
6+
7+
namespace Semmle.Extraction.CSharp.Entities.Expressions
8+
{
9+
internal class BinaryPattern : Expression
10+
{
11+
public BinaryPattern(Context cx, BinaryPatternSyntax syntax, IExpressionParentEntity parent, int child) :
12+
base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), GetKind(syntax.OperatorToken, syntax), parent, child, false, null))
13+
{
14+
Pattern.Create(cx, syntax.Left, this, 0);
15+
Pattern.Create(cx, syntax.Right, this, 1);
16+
}
17+
18+
private static ExprKind GetKind(SyntaxToken operatorToken, BinaryPatternSyntax syntax)
19+
{
20+
return operatorToken.Kind() switch
21+
{
22+
SyntaxKind.AndKeyword => ExprKind.AND_PATTERN,
23+
SyntaxKind.OrKeyword => ExprKind.OR_PATTERN,
24+
_ => throw new InternalError(syntax, $"Operator '{operatorToken.Kind()}' is not supported in binary patterns.")
25+
};
26+
}
27+
}
28+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ internal static Expression Create(Context cx, PatternSyntax syntax, IExpressionP
2323
case UnaryPatternSyntax unaryPattern:
2424
return new UnaryPattern(cx, unaryPattern, parent, child);
2525

26+
case BinaryPatternSyntax binaryPattern:
27+
return new BinaryPattern(cx, binaryPattern, parent, child);
28+
2629
case DeclarationPatternSyntax declPattern:
2730
// Creates a single local variable declaration.
2831
{

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ public enum ExprKind
121121
LE_PATTERN = 124,
122122
GE_PATTERN = 125,
123123
NOT_PATTERN = 126,
124+
AND_PATTERN = 127,
125+
OR_PATTERN = 128,
124126
FUNCTION_POINTER_INVOCATION = 129,
125127
}
126128
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,11 @@ private predicate hasChildPattern(ControlFlowElement pm, Expr child) {
301301
mid instanceof @unary_pattern_expr and
302302
child = mid.getChild(0)
303303
)
304+
or
305+
exists(Expr mid | hasChildPattern(pm, mid) and mid instanceof @binary_pattern_expr |
306+
child = mid.getChild(0) or
307+
child = mid.getChild(1)
308+
)
304309
}
305310

306311
/**
@@ -502,6 +507,29 @@ class NotPatternExpr extends UnaryPatternExpr, @not_pattern_expr {
502507
override string getAPrimaryQlClass() { result = "NotPatternExpr" }
503508
}
504509

510+
/** A binary pattern. For example, `1 or 2`. */
511+
class BinaryPatternExpr extends PatternExpr, @binary_pattern_expr {
512+
/** Gets the left pattern. */
513+
PatternExpr getLeftOperand() { result = this.getChild(0) }
514+
515+
/** Gets the right pattern. */
516+
PatternExpr getRightOperand() { result = this.getChild(1) }
517+
}
518+
519+
/** A binary or pattern. For example, `1 or 2`. */
520+
class OrPatternExpr extends BinaryPatternExpr, @or_pattern_expr {
521+
override string toString() { result = "... or ..." }
522+
523+
override string getAPrimaryQlClass() { result = "OrPatternExpr" }
524+
}
525+
526+
/** A binary and pattern. For example, `< 1 and > 2`. */
527+
class AndPatternExpr extends BinaryPatternExpr, @and_pattern_expr {
528+
override string toString() { result = "... and ..." }
529+
530+
override string getAPrimaryQlClass() { result = "AndPatternExpr" }
531+
}
532+
505533
/**
506534
* An expression or statement that matches the value of an expression against
507535
* a pattern. Either an `is` expression or a `case` expression/statement.

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,8 @@ case @expr.kind of
10321032
| 124 = @le_pattern_expr
10331033
| 125 = @ge_pattern_expr
10341034
| 126 = @not_pattern_expr
1035+
| 127 = @and_pattern_expr
1036+
| 128 = @or_pattern_expr
10351037
| 129 = @function_pointer_invocation_expr
10361038
;
10371039

@@ -1040,6 +1042,7 @@ case @expr.kind of
10401042
@pattern_match = @case | @is_expr;
10411043
@unary_pattern_expr = @not_pattern_expr;
10421044
@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
1045+
@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
10431046

10441047
@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
10451048
@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
3+
public class BinaryPattern
4+
{
5+
public int P1 { get; set; }
6+
7+
public static bool M1(char c) =>
8+
c is 'a' or 'b';
9+
public static bool M2(object c) =>
10+
c is object o and BinaryPattern { P1: 1 } u;
11+
public static bool M3(object c) =>
12+
c is object o and BinaryPattern u;
13+
14+
public static string M4(int i)
15+
{
16+
return i switch
17+
{
18+
1 or 2 => "1 or 2",
19+
_ => "other"
20+
};
21+
}
22+
}

csharp/ql/test/library-tests/csharp9/PrintAst.expected

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,69 @@ AnonymousObjectCreation.cs:
5454
# 25| 1: [TypeMention] int
5555
# 25| 0: [LocalVariableAccess] access to local variable list
5656
# 25| 1: [ObjectCreation] object creation of type List<Int32>
57+
BinaryPattern.cs:
58+
# 3| [Class] BinaryPattern
59+
# 5| 5: [Property] P1
60+
# 5| -1: [TypeMention] int
61+
# 5| 3: [Getter] get_P1
62+
# 5| 4: [Setter] set_P1
63+
#-----| 2: (Parameters)
64+
# 5| 0: [Parameter] value
65+
# 7| 6: [Method] M1
66+
# 7| -1: [TypeMention] bool
67+
#-----| 2: (Parameters)
68+
# 7| 0: [Parameter] c
69+
# 7| -1: [TypeMention] char
70+
# 8| 4: [IsExpr] ... is ...
71+
# 8| 0: [ParameterAccess] access to parameter c
72+
# 8| 1: [OrPatternExpr] ... or ...
73+
# 8| 0: [CharLiteral,ConstantPatternExpr] a
74+
# 8| 1: [CharLiteral,ConstantPatternExpr] b
75+
# 9| 7: [Method] M2
76+
# 9| -1: [TypeMention] bool
77+
#-----| 2: (Parameters)
78+
# 9| 0: [Parameter] c
79+
# 9| -1: [TypeMention] object
80+
# 10| 4: [IsExpr] ... is ...
81+
# 10| 0: [ParameterAccess] access to parameter c
82+
# 10| 1: [AndPatternExpr] ... and ...
83+
# 10| 0: [VariablePatternExpr] Object o
84+
# 10| 0: [TypeMention] object
85+
# 10| 1: [RecursivePatternExpr] { ... }
86+
# 10| 0: [LocalVariableDeclExpr] BinaryPattern u
87+
# 10| 1: [TypeAccess] access to type BinaryPattern
88+
# 10| 0: [TypeMention] BinaryPattern
89+
# 10| 3: [PropertyPatternExpr] { ... }
90+
# 10| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 1
91+
# 11| 8: [Method] M3
92+
# 11| -1: [TypeMention] bool
93+
#-----| 2: (Parameters)
94+
# 11| 0: [Parameter] c
95+
# 11| -1: [TypeMention] object
96+
# 12| 4: [IsExpr] ... is ...
97+
# 12| 0: [ParameterAccess] access to parameter c
98+
# 12| 1: [AndPatternExpr] ... and ...
99+
# 12| 0: [VariablePatternExpr] Object o
100+
# 12| 0: [TypeMention] object
101+
# 12| 1: [VariablePatternExpr] BinaryPattern u
102+
# 12| 0: [TypeMention] BinaryPattern
103+
# 14| 9: [Method] M4
104+
# 14| -1: [TypeMention] string
105+
#-----| 2: (Parameters)
106+
# 14| 0: [Parameter] i
107+
# 14| -1: [TypeMention] int
108+
# 15| 4: [BlockStmt] {...}
109+
# 16| 0: [ReturnStmt] return ...;
110+
# 16| 0: [SwitchExpr] ... switch { ... }
111+
# 16| -1: [ParameterAccess] access to parameter i
112+
# 18| 0: [SwitchCaseExpr] ... => ...
113+
# 18| 0: [OrPatternExpr] ... or ...
114+
# 18| 0: [ConstantPatternExpr,IntLiteral] 1
115+
# 18| 1: [ConstantPatternExpr,IntLiteral] 2
116+
# 18| 2: [StringLiteral] "1 or 2"
117+
# 19| 1: [SwitchCaseExpr] ... => ...
118+
# 19| 0: [DiscardPatternExpr] _
119+
# 19| 2: [StringLiteral] "other"
57120
Discard.cs:
58121
# 3| [Class] Discard
59122
# 5| 5: [Method] M1
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| BinaryPattern.cs:8:14:8:23 | ... or ... | BinaryPattern.cs:8:14:8:16 | a | BinaryPattern.cs:8:21:8:23 | b |
2+
| BinaryPattern.cs:10:14:10:51 | ... and ... | BinaryPattern.cs:10:14:10:21 | Object o | BinaryPattern.cs:10:27:10:51 | { ... } |
3+
| BinaryPattern.cs:12:14:12:41 | ... and ... | BinaryPattern.cs:12:14:12:21 | Object o | BinaryPattern.cs:12:27:12:41 | BinaryPattern u |
4+
| BinaryPattern.cs:18:13:18:18 | ... or ... | BinaryPattern.cs:18:13:18:13 | 1 | BinaryPattern.cs:18:18:18:18 | 2 |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import csharp
2+
3+
from BinaryPatternExpr pattern
4+
select pattern, pattern.getLeftOperand(), pattern.getRightOperand()

0 commit comments

Comments
 (0)