Merge pull request #4656 from tamasvajk/feature/csharp9-not-pattern

C#: Extract unary patterns
This commit is contained in:
Tamás Vajk
2021-01-15 09:44:53 +01:00
committed by GitHub
15 changed files with 6549 additions and 2586 deletions

View File

@@ -0,0 +1,3 @@
lgtm,codescanning
* The `UnaryPatternExpr` and `NotPatternExpr` classes have been added to support
C# 9 unary `not` pattern.

View File

@@ -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.
{

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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"

View 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"
};
}
}

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -0,0 +1,4 @@
import csharp
from UnaryPatternExpr pattern
select pattern, pattern.getAChild()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add 'not_pattern_expr' to the list of 'expr' types.
compatibility: backwards