mirror of
https://github.com/github/codeql.git
synced 2026-04-25 00:35:20 +02:00
Merge pull request #4656 from tamasvajk/feature/csharp9-not-pattern
C#: Extract unary patterns
This commit is contained in:
3
csharp/change-notes/2021-01-14-Unary-pattern.md
Normal file
3
csharp/change-notes/2021-01-14-Unary-pattern.md
Normal file
@@ -0,0 +1,3 @@
|
||||
lgtm,codescanning
|
||||
* The `UnaryPatternExpr` and `NotPatternExpr` classes have been added to support
|
||||
C# 9 unary `not` pattern.
|
||||
@@ -20,6 +20,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
case TypePatternSyntax typePattern:
|
||||
return Expressions.TypeAccess.Create(cx, typePattern.Type, parent, child);
|
||||
|
||||
case UnaryPatternSyntax unaryPattern:
|
||||
return new UnaryPattern(cx, unaryPattern, parent, child);
|
||||
|
||||
case DeclarationPatternSyntax declPattern:
|
||||
// Creates a single local variable declaration.
|
||||
{
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
internal class UnaryPattern : Expression
|
||||
{
|
||||
public UnaryPattern(Context cx, UnaryPatternSyntax syntax, IExpressionParentEntity parent, int child) :
|
||||
base(new ExpressionInfo(cx, NullType.Create(cx), cx.Create(syntax.GetLocation()), ExprKind.NOT_PATTERN, parent, child, false, null))
|
||||
{
|
||||
Pattern.Create(cx, syntax.Pattern, this, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,6 +115,7 @@ namespace Semmle.Extraction.Kinds
|
||||
SWITCH_CASE = 118,
|
||||
ASSIGN_COALESCE = 119,
|
||||
SUPPRESS_NULLABLE_WARNING = 120,
|
||||
NAMESPACE_ACCESS = 121
|
||||
NAMESPACE_ACCESS = 121,
|
||||
NOT_PATTERN = 126
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +295,12 @@ private predicate hasChildPattern(ControlFlowElement pm, Expr child) {
|
||||
child = mid.getChild(2).getAChildExpr() or
|
||||
child = mid.getChild(3).getAChildExpr()
|
||||
)
|
||||
or
|
||||
exists(Expr mid |
|
||||
hasChildPattern(pm, mid) and
|
||||
mid instanceof @unary_pattern_expr and
|
||||
child = mid.getChild(0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -444,6 +450,19 @@ class PositionalPatternExpr extends Expr, @positional_pattern_expr {
|
||||
override string getAPrimaryQlClass() { result = "PositionalPatternExpr" }
|
||||
}
|
||||
|
||||
/** A unary pattern. For example, `not 1`. */
|
||||
class UnaryPatternExpr extends PatternExpr, @unary_pattern_expr {
|
||||
/** Gets the underlying pattern. */
|
||||
PatternExpr getPattern() { result = this.getChild(0) }
|
||||
}
|
||||
|
||||
/** A not pattern. For example, `not 1`. */
|
||||
class NotPatternExpr extends UnaryPatternExpr, @not_pattern_expr {
|
||||
override string toString() { result = "not ..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NotPatternExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression or statement that matches the value of an expression against
|
||||
* a pattern. Either an `is` expression or a `case` expression/statement.
|
||||
|
||||
@@ -1009,11 +1009,14 @@ case @expr.kind of
|
||||
| 119 = @assign_coalesce_expr
|
||||
| 120 = @suppress_nullable_warning_expr
|
||||
| 121 = @namespace_access_expr
|
||||
/* C# 9.0 */
|
||||
| 126 = @not_pattern_expr
|
||||
;
|
||||
|
||||
@switch = @switch_stmt | @switch_expr;
|
||||
@case = @case_stmt | @switch_case_expr;
|
||||
@pattern_match = @case | @is_expr;
|
||||
@unary_pattern_expr = @not_pattern_expr;
|
||||
|
||||
@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
|
||||
@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -764,3 +764,59 @@ TypePattern.cs:
|
||||
# 14| 0: [VariablePatternExpr] Object o
|
||||
# 14| 0: [TypeMention] object
|
||||
# 14| 2: [LocalVariableAccess] access to local variable o
|
||||
UnaryPattern.cs:
|
||||
# 3| [Class] UnaryPattern
|
||||
# 5| 5: [Property] P1
|
||||
# 5| -1: [TypeMention] int
|
||||
# 5| 3: [Getter] get_P1
|
||||
# 5| 4: [Setter] set_P1
|
||||
#-----| 2: (Parameters)
|
||||
# 5| 0: [Parameter] value
|
||||
# 7| 6: [Method] M1
|
||||
# 7| -1: [TypeMention] bool
|
||||
#-----| 2: (Parameters)
|
||||
# 7| 0: [Parameter] c
|
||||
# 7| -1: [TypeMention] char
|
||||
# 8| 4: [IsExpr] ... is ...
|
||||
# 8| 0: [ParameterAccess] access to parameter c
|
||||
# 8| 1: [NotPatternExpr] not ...
|
||||
# 8| 0: [CharLiteral,ConstantPatternExpr] a
|
||||
# 9| 7: [Method] M2
|
||||
# 9| -1: [TypeMention] bool
|
||||
#-----| 2: (Parameters)
|
||||
# 9| 0: [Parameter] c
|
||||
# 9| -1: [TypeMention] object
|
||||
# 10| 4: [IsExpr] ... is ...
|
||||
# 10| 0: [ParameterAccess] access to parameter c
|
||||
# 10| 1: [NotPatternExpr] not ...
|
||||
# 10| 0: [ConstantPatternExpr,NullLiteral] null
|
||||
# 11| 8: [Method] M3
|
||||
# 11| -1: [TypeMention] bool
|
||||
#-----| 2: (Parameters)
|
||||
# 11| 0: [Parameter] c
|
||||
# 11| -1: [TypeMention] object
|
||||
# 12| 4: [IsExpr] ... is ...
|
||||
# 12| 0: [ParameterAccess] access to parameter c
|
||||
# 12| 1: [NotPatternExpr] not ...
|
||||
# 12| 0: [RecursivePatternExpr] { ... }
|
||||
# 12| 0: [LocalVariableDeclExpr] UnaryPattern u
|
||||
# 12| 1: [TypeAccess] access to type UnaryPattern
|
||||
# 12| 0: [TypeMention] UnaryPattern
|
||||
# 12| 3: [PropertyPatternExpr] { ... }
|
||||
# 12| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 1
|
||||
# 14| 9: [Method] M4
|
||||
# 14| -1: [TypeMention] string
|
||||
#-----| 2: (Parameters)
|
||||
# 14| 0: [Parameter] i
|
||||
# 14| -1: [TypeMention] int
|
||||
# 15| 4: [BlockStmt] {...}
|
||||
# 16| 0: [ReturnStmt] return ...;
|
||||
# 16| 0: [SwitchExpr] ... switch { ... }
|
||||
# 16| -1: [ParameterAccess] access to parameter i
|
||||
# 18| 0: [SwitchCaseExpr] ... => ...
|
||||
# 18| 0: [NotPatternExpr] not ...
|
||||
# 18| 0: [ConstantPatternExpr,IntLiteral] 1
|
||||
# 18| 2: [StringLiteral] "not 1"
|
||||
# 19| 1: [SwitchCaseExpr] ... => ...
|
||||
# 19| 0: [DiscardPatternExpr] _
|
||||
# 19| 2: [StringLiteral] "other"
|
||||
|
||||
22
csharp/ql/test/library-tests/csharp9/UnaryPattern.cs
Normal file
22
csharp/ql/test/library-tests/csharp9/UnaryPattern.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
public class UnaryPattern
|
||||
{
|
||||
public int P1 { get; set; }
|
||||
|
||||
public static bool M1(char c) =>
|
||||
c is not 'a';
|
||||
public static bool M2(object c) =>
|
||||
c is not null;
|
||||
public static bool M3(object c) =>
|
||||
c is not UnaryPattern { P1: 1 } u;
|
||||
|
||||
public static string M4(int i)
|
||||
{
|
||||
return i switch
|
||||
{
|
||||
not 1 => "not 1",
|
||||
_ => "other"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4,3 +4,4 @@
|
||||
| InitOnlyProperty.cs:14:37:14:39 | set_Prop2 | set |
|
||||
| InitOnlyProperty.cs:20:38:20:41 | set_Prop1 | init |
|
||||
| InitOnlyProperty.cs:24:9:24:12 | set_Prop2 | init |
|
||||
| UnaryPattern.cs:5:26:5:28 | set_P1 | set |
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| UnaryPattern.cs:8:14:8:20 | not ... | UnaryPattern.cs:8:18:8:20 | a |
|
||||
| UnaryPattern.cs:10:14:10:21 | not ... | UnaryPattern.cs:10:18:10:21 | null |
|
||||
| UnaryPattern.cs:12:14:12:41 | not ... | UnaryPattern.cs:12:18:12:41 | { ... } |
|
||||
| UnaryPattern.cs:18:13:18:17 | not ... | UnaryPattern.cs:18:17:18:17 | 1 |
|
||||
4
csharp/ql/test/library-tests/csharp9/unaryPattern.ql
Normal file
4
csharp/ql/test/library-tests/csharp9/unaryPattern.ql
Normal file
@@ -0,0 +1,4 @@
|
||||
import csharp
|
||||
|
||||
from UnaryPatternExpr pattern
|
||||
select pattern, pattern.getAChild()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add 'not_pattern_expr' to the list of 'expr' types.
|
||||
compatibility: backwards
|
||||
Reference in New Issue
Block a user