C#: Implement recursive patterns

This commit is contained in:
calum
2019-04-25 11:23:51 +01:00
committed by Calum Grant
parent 318068b52f
commit 1428d0ba93
26 changed files with 1495 additions and 58 deletions

View File

@@ -1,15 +1,23 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Kinds;
using Semmle.Extraction.Entities;
using Microsoft.CodeAnalysis;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
class Discard : Expression<NameSyntax>
class Discard : Expression
{
public Discard(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.DISCARD))
{
}
protected override void Populate()
public Discard(Context cx, DiscardDesignationSyntax discard, IExpressionParentEntity parent, int child) :
base(new ExpressionInfo(cx, Type.Create(cx, cx.Model(discard).GetTypeInfo(discard).Type), cx.Create(discard.GetLocation()), ExprKind.DISCARD, parent, child, false, null))
{
}
public Discard(Context cx, DiscardPatternSyntax pattern, IExpressionParentEntity parent, int child) :
base(new ExpressionInfo(cx, Type.Create(cx, cx.Model(pattern).GetTypeInfo(pattern).Type), cx.Create(pattern.GetLocation()), ExprKind.DISCARD, parent, child, false, null))
{
}
}

View File

@@ -238,6 +238,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.IndexExpression:
return Unary.Create(info.SetKind(ExprKind.INDEX));
case SyntaxKind.SwitchExpression:
return Switch.Create(info);
default:
info.Context.ModelError(info.Node, $"Unhandled expression '{info.Node}' of kind '{info.Node.Kind()}'");
return new Unknown(info);

View File

@@ -6,6 +6,126 @@ using Semmle.Extraction.Entities;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
static class PatternExtensions
{
public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IExpressionParentEntity parent, int child)
{
switch (syntax)
{
case ConstantPatternSyntax constantPattern:
return Expression.Create(cx, constantPattern.Expression, parent, child);
case DeclarationPatternSyntax declPattern:
// Creates a single local variable declaration.
{
if (declPattern.Designation is VariableDesignationSyntax designation && cx.Model(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
{
var type = Type.Create(cx, symbol.Type);
return VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, parent, child);
}
throw new InternalError(syntax, "Is pattern not handled");
}
case RecursivePatternSyntax recPattern:
return new RecursivePattern(cx, recPattern, parent, child, false);
case VarPatternSyntax varPattern:
switch(varPattern.Designation)
{
case ParenthesizedVariableDesignationSyntax parDesignation:
return VariableDeclaration.CreateParenthesized(cx, varPattern, parDesignation, parent, child);
case SingleVariableDesignationSyntax varDesignation:
if (cx.Model(syntax).GetDeclaredSymbol(varDesignation) is ILocalSymbol symbol2)
{
var type = Type.Create(cx, symbol2.Type);
return VariableDeclaration.Create(cx, symbol2, type, cx.Create(syntax.GetLocation()), cx.Create(varDesignation.GetLocation()), false, parent, child);
}
else
{
throw new InternalError(varPattern, "Unable to get the declared symbol of the var pattern designation.");
}
default:
throw new InternalError("var pattern designation is unhandled");
}
case DiscardPatternSyntax dp:
return new Discard(cx, dp, parent, child);
default:
throw new InternalError(syntax, "Is pattern not handled");
}
}
}
class PropertyPattern : Expression
{
internal PropertyPattern(Context cx, PropertyPatternClauseSyntax pp, IExpressionParentEntity parent, int child) :
base(new ExpressionInfo(cx, Type.Create(cx, null), cx.Create(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null))
{
child = 0;
foreach (var sub in pp.Subpatterns)
{
cx.CreatePattern(sub.Pattern, this, child++);
}
}
}
class PositionalPattern : Expression
{
internal PositionalPattern(Context cx, PositionalPatternClauseSyntax posPc, IExpressionParentEntity parent, int child) :
base(new ExpressionInfo(cx, Type.Create(cx, null), cx.Create(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null))
{
child = 0;
foreach (var sub in posPc.Subpatterns)
{
cx.CreatePattern(sub.Pattern, this, child++);
}
}
}
class RecursivePattern : Expression
{
/// <summary>
/// Creates and populates a recursive pattern.
/// </summary>
/// <param name="cx">The extraction context.</param>
/// <param name="syntax">The syntax node of the recursive pattern.</param>
/// <param name="parent">The parent pattern/expression.</param>
/// <param name="child">The child index of this pattern.</param>
/// <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>
public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionParentEntity parent, int child, bool isTopLevel) :
base(new ExpressionInfo(cx, Type.Create(cx, null), cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null))
{
if(!isTopLevel)
{
// Extract the type access
if(syntax.Type is TypeSyntax t)
Expressions.TypeAccess.Create(cx, t, this, 1);
// Extract the local variable declaration
if (syntax.Designation is VariableDesignationSyntax designation && cx.Model(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
{
var type = Type.Create(cx, symbol.Type);
VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, this, 0);
}
}
if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc)
{
new PositionalPattern(cx, posPc, this, 2);
}
if (syntax.PropertyPatternClause is PropertyPatternClauseSyntax pc)
{
new PropertyPattern(cx, pc, this, 3);
}
}
}
class IsPattern : Expression<IsPatternExpressionSyntax>
{
private IsPattern(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.IS))
@@ -18,7 +138,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
if (!isVar)
Expressions.TypeAccess.Create(cx, optionalType, this, 1);
if (cx.Model(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
if (!(designation is null) && cx.Model(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
{
var type = Type.Create(cx, symbol.Type);
@@ -43,6 +163,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case DeclarationPatternSyntax declPattern:
PopulatePattern(declPattern, declPattern.Type, default(SyntaxToken), declPattern.Designation);
return;
case RecursivePatternSyntax recPattern:
PopulatePattern(recPattern, recPattern.Type, default(SyntaxToken), recPattern.Designation);
new RecursivePattern(cx, recPattern, this, 4, true);
return;
default:
throw new InternalError(Syntax, "Is pattern not handled");
}

View File

@@ -0,0 +1,22 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Kinds;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
class RangeExpression : Expression<RangeExpressionSyntax>
{
private RangeExpression(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.RANGE))
{
}
protected override void Populate()
{
if (!(Syntax.LeftOperand is null))
Expression.Create(cx, Syntax.LeftOperand, this, 0);
if (!(Syntax.RightOperand is null))
Expression.Create(cx, Syntax.RightOperand, this, 1);
}
public static Expression Create(ExpressionNodeInfo info) => new RangeExpression(info).TryPopulate();
}
}

View File

@@ -0,0 +1,39 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Entities;
using Semmle.Extraction.Kinds;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
class Switch : Expression<SwitchExpressionSyntax>
{
private Switch(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.SWITCH))
{
}
public static Expression Create(ExpressionNodeInfo info) => new Switch(info).TryPopulate();
public Expression SwitchedExpr { get; private set; }
protected override void Populate()
{
SwitchedExpr = Expression.Create(cx, Syntax.GoverningExpression, this, -1);
int child = 0;
foreach(var arm in Syntax.Arms)
{
new SwitchCase(cx, arm, this, child++);
}
}
}
class SwitchCase : Expression
{
internal SwitchCase(Context cx, SwitchExpressionArmSyntax arm, Switch parent, int child) :
base(new ExpressionInfo(cx, parent.SwitchedExpr.Type, cx.Create(arm.GetLocation()), ExprKind.SWITCH_CASE, parent, child, false, null))
{
cx.CreatePattern(arm.Pattern, this, 0);
if (arm.WhenClause is WhenClauseSyntax when)
Expression.Create(cx, when.Condition, this, 1);
Expression.Create(cx, arm.Expression, this, 2);
}
}
}

View File

@@ -26,13 +26,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
if (variableSymbol == null)
{
cx.ModelError(node, "Failed to determine local variable");
return new VariableDeclaration(cx, node, null, isVar, parent, child);
return Create(cx, node, null, isVar, parent, child);
}
var type = Type.Create(cx, variableSymbol.Type);
var location = cx.Create(designation.GetLocation());
var ret = new VariableDeclaration(cx, designation, type, isVar, parent, child);
var ret = Create(cx, designation, type, isVar, parent, child);
cx.Try(null, null, () => LocalVariable.Create(cx, variableSymbol, ret, isVar, location));
return ret;
}
@@ -41,7 +41,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
/// Create a tuple expression representing a parenthesized variable declaration.
/// That is, we consider `var (x, y) = ...` to be equivalent to `(var x, var y) = ...`.
/// </summary>
static Expression CreateParenthesized(Context cx, DeclarationExpressionSyntax node, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
public static Expression CreateParenthesized(Context cx, DeclarationExpressionSyntax node, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
{
var type = Type.Create(cx, null); // Should ideally be a corresponding tuple type
var tuple = new Expression(new ExpressionInfo(cx, type, cx.Create(node.GetLocation()), ExprKind.TUPLE, parent, child, false, null));
@@ -56,41 +56,73 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return tuple;
}
public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPattern, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
{
var type = Type.Create(cx, null); // Should ideally be a corresponding tuple type
var tuple = new Expression(new ExpressionInfo(cx, type, cx.Create(varPattern.GetLocation()), ExprKind.TUPLE, parent, child, false, null));
cx.Try(null, null, () =>
{
var child0 = 0;
foreach (var variable in designation.Variables)
switch(variable)
{
case ParenthesizedVariableDesignationSyntax paren:
CreateParenthesized(cx, varPattern, paren, tuple, child0++);
break;
case SingleVariableDesignationSyntax single:
if (cx.Model(variable).GetDeclaredSymbol(single) is ILocalSymbol local)
{
var decl = Create(cx, variable, Type.Create(cx, local.Type), true, tuple, child0++);
var id = single.Identifier;
var declSymbol = cx.Model(single).GetDeclaredSymbol(single);
var location = cx.Create(id.GetLocation());
LocalVariable.Create(cx, local, decl, true, location);
}
else
{
throw new InternalError(single, "Failed to access local variable");
}
break;
case DiscardDesignationSyntax discard:
new Discard(cx, discard, tuple, child0++);
break;
default:
throw new InternalError(variable, "Unhandled designation type");
}
});
return tuple;
}
static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
{
var single = designation as SingleVariableDesignationSyntax;
if (single != null)
return CreateSingle(cx, node, single, parent, child);
var paren = designation as ParenthesizedVariableDesignationSyntax;
if (paren != null)
return CreateParenthesized(cx, node, paren, parent, child);
var discard = designation as DiscardDesignationSyntax;
if (discard != null)
switch(designation)
{
var type = cx.Model(node).GetTypeInfo(node).Type;
return new VariableDeclaration(cx, node, Type.Create(cx, type), node.Type.IsVar, parent, child);
case SingleVariableDesignationSyntax single:
return CreateSingle(cx, node, single, parent, child);
case ParenthesizedVariableDesignationSyntax paren:
return CreateParenthesized(cx, node, paren, parent, child);
case DiscardDesignationSyntax discard:
var type = cx.Model(discard).GetTypeInfo(discard).Type;
return Create(cx, node, Type.Create(cx, type), node.Type.IsVar, parent, child);
default:
cx.ModelError(node, "Failed to determine designation type");
return Create(cx, node, null, node.Type.IsVar, parent, child);
}
cx.ModelError(node, "Failed to determine designation type");
return new VariableDeclaration(cx, node, null, node.Type.IsVar, parent, child);
}
public static Expression Create(Context cx, DeclarationExpressionSyntax node, IExpressionParentEntity parent, int child)
{
return Create(cx, node, node.Designation, parent, child);
}
public static Expression Create(Context cx, DeclarationExpressionSyntax node, IExpressionParentEntity parent, int child) =>
Create(cx, node, node.Designation, parent, child);
VariableDeclaration(Context cx, CSharpSyntaxNode d, Type type, bool isVar, IExpressionParentEntity parent, int child)
: base(new ExpressionInfo(cx, type, cx.Create(d.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null))
{
}
public static VariableDeclaration Create(Context cx, CSharpSyntaxNode c, Type type, bool isVar, IExpressionParentEntity parent, int child) =>
new VariableDeclaration(new ExpressionInfo(cx, type, cx.Create(c.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null));
public static VariableDeclaration Create(Context cx, CatchDeclarationSyntax d, bool isVar, IExpressionParentEntity parent, int child)
{
var type = Type.Create(cx, cx.Model(d).GetDeclaredSymbol(d).Type);
var ret = new VariableDeclaration(cx, d, type, isVar, parent, child);
var ret = Create(cx, d, type, isVar, parent, child);
cx.Try(d, null, () =>
{
var id = d.Identifier;
@@ -102,9 +134,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ret;
}
public static VariableDeclaration Create(Context cx, VariableDeclaratorSyntax d, Type type, bool isVar, IExpressionParentEntity parent, int child)
public static VariableDeclaration CreateDeclarator(Context cx, VariableDeclaratorSyntax d, Type type, bool isVar, IExpressionParentEntity parent, int child)
{
var ret = new VariableDeclaration(cx, d, type, isVar, parent, child);
var ret = Create(cx, d, type, isVar, parent, child);
cx.Try(d, null, () =>
{
var id = d.Identifier;
@@ -137,7 +169,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
foreach (var v in decl.Variables)
{
VariableDeclaration.Create(cx, v, type, decl.Type.IsVar, parent, child);
VariableDeclaration.CreateDeclarator(cx, v, type, decl.Type.IsVar, parent, child);
child += childIncrement;
}
}

View File

@@ -73,14 +73,29 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
if(!isVar)
Expressions.TypeAccess.Create(cx, optionalType, this, 1);
if (cx.Model(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
switch (designation)
{
var type = Type.Create(cx, symbol.Type);
case SingleVariableDesignationSyntax single:
if (cx.Model(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
{
var type = Type.Create(cx, symbol.Type);
if (isVar)
new Expression(new ExpressionInfo(cx, type, cx.Create(varKeyword.GetLocation()), ExprKind.TYPE_ACCESS, this, 1, false, null));
if (isVar)
new Expression(new ExpressionInfo(cx, type, cx.Create(varKeyword.GetLocation()), ExprKind.TYPE_ACCESS, this, 1, false, null));
Expressions.VariableDeclaration.Create(cx, symbol, type, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 0);
Expressions.VariableDeclaration.Create(cx, symbol, type, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 0);
}
break;
case DiscardDesignationSyntax discard:
new Expressions.Discard(cx, discard, this, 0);
break;
case null:
break;
case ParenthesizedVariableDesignationSyntax paren:
Expressions.VariableDeclaration.CreateParenthesized(cx, pattern as VarPatternSyntax, paren, this, 0);
break;
default:
throw new InternalError(pattern, "Unhandled designation in case statement");
}
}
@@ -97,6 +112,10 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
case ConstantPatternSyntax pattern:
Expression.Create(cx, pattern.Expression, this, 0);
break;
case RecursivePatternSyntax recPattern:
PopulatePattern(recPattern, recPattern.Type, default(SyntaxToken), recPattern.Designation);
new Expressions.RecursivePattern(cx, recPattern, this, 4, true);
break;
default:
throw new InternalError(Stmt, "Case pattern not handled");
}

View File

@@ -107,6 +107,11 @@ namespace Semmle.Extraction.Kinds
REF = 110,
DISCARD = 111,
RANGE = 112,
INDEX = 113
INDEX = 113,
SWITCH = 114,
RECURSIVE_PATTERN = 115,
PROPERTY_PATTERN = 116,
POSITIONAL_PATTERN = 117,
SWITCH_CASE = 118
}
}

View File

@@ -7,8 +7,8 @@ namespace Semmle.Extraction.Entities
: base(cx, init) { }
public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) =>
loc == null || loc.Kind == Microsoft.CodeAnalysis.LocationKind.None ?
GeneratedLocation.Create(cx) : loc.IsInSource ? SourceLocation.Create(cx, loc)
(loc == null || loc.Kind == Microsoft.CodeAnalysis.LocationKind.None) ? GeneratedLocation.Create(cx)
: loc.IsInSource ? SourceLocation.Create(cx, loc)
: Assembly.Create(cx, loc);
public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol;

View File

@@ -283,7 +283,8 @@ class ConstCase extends LabeledStmt, CaseStmt {
ConstCase() {
expr = this.getChild(0) and
not expr instanceof LocalVariableDeclExpr
not expr instanceof LocalVariableDeclExpr and
not exists(this.getChild(1))
}
/** Gets the case expression. */
@@ -309,7 +310,10 @@ class ConstCase extends LabeledStmt, CaseStmt {
* ```
*/
class TypeCase extends LabeledStmt, CaseStmt {
TypeCase() { this.getChild(1) instanceof TypeAccess }
TypeCase() {
this.getChild(1) instanceof TypeAccess and
not this.getChild(4) instanceof RecursivePatternExpr
}
/**
* Gets the local variable declaration of this type case, if any. For example,
@@ -369,6 +373,38 @@ class TypeCase extends LabeledStmt, CaseStmt {
}
}
/**
* A recursive pattern case, for example `case string { Length: 0 } empty:`.
*/
class RecursivePatternCase extends LabeledStmt, CaseStmt {
RecursivePatternExpr pattern;
RecursivePatternCase() { pattern = this.getChild(4) }
override string toString() { result = "case { ... }:" }
/**
* Gets the type access of this recursive pattern case, if any.
* For example, `string` in `case string { Length: 0 } empty:`.
*/
TypeAccess getTypeAccess() { result = getChild(1) }
/**
* Gets the checked type of this recursive pattern, if any.
* For example, `string` in `case string { Length: 0 } empty:`.
*/
Type getCheckedType() { result = getTypeAccess().getType() }
/**
* Gets the recursive pattern of this case.
* For example, `{ Length: 0 }` in `case string { Length: 0 } empty:`.
*/
RecursivePatternExpr getRecursivePattern() { result = pattern }
LocalVariableDeclExpr getVariableDeclExpr() { result = getChild(0) }
}
/**
* A default case of a `switch` statement, for example `default:` on
* line 3 in

View File

@@ -460,6 +460,7 @@ module ControlFlow {
not this instanceof SwitchStmt and
not this instanceof ConstCase and
not this instanceof TypeCase and
not this instanceof RecursivePatternCase and
not this instanceof LoopStmt and
not this instanceof TryStmt and
not this instanceof SpecificCatchClause and
@@ -645,7 +646,9 @@ module ControlFlow {
not this instanceof ArrayCreation and
not this instanceof QualifiedWriteAccess and
not this instanceof AccessorWrite and
not this instanceof NoNodeExpr
not this instanceof NoNodeExpr and
not this instanceof SwitchExpr and
not this instanceof SwitchCaseExpr
}
override ControlFlowElement getChildElement(int i) { result = getExprChildElement(this, i) }
@@ -709,6 +712,8 @@ module ControlFlow {
or
this instanceof TypeCase
or
this instanceof RecursivePatternCase
or
this instanceof TryStmt
or
this instanceof SpecificCatchClause
@@ -724,6 +729,10 @@ module ControlFlow {
this instanceof NullCoalescingExpr
or
this instanceof ConditionalExpr
or
this instanceof SwitchExpr
or
this instanceof SwitchCaseExpr
}
}
@@ -923,7 +932,8 @@ module ControlFlow {
// Last case exits with a non-match
exists(int last | last = max(int i | exists(ss.getCase(i))) |
result = lastConstCaseNoMatch(ss.getCase(last), c) or
result = lastTypeCaseNoMatch(ss.getCase(last), c)
result = lastTypeCaseNoMatch(ss.getCase(last), c) or
result = lastRecursivePatternCaseNoMatch(ss.getCase(last), c)
)
or
// Last statement exits with any non-break completion
@@ -947,6 +957,8 @@ module ControlFlow {
result = lastTypeCaseNoMatch(tc, c)
)
or
cfe = any(RecursivePatternCase rpc | result = lastRecursivePatternCaseNoMatch(rpc, c))
or
cfe = any(CaseStmt cs |
// Condition exists with a `false` completion
result = lastCaseCondition(cs, c) and
@@ -1132,6 +1144,9 @@ module ControlFlow {
c.isValidFor(result) and
not c instanceof NormalCompletion
)
or
// Result of a switch expression
result = lastSwitchExpr(cfe, c)
}
private ControlFlowElement lastConstCaseNoMatch(ConstCase cc, MatchingCompletion c) {
@@ -1139,10 +1154,28 @@ module ControlFlow {
not c.isMatch()
}
private ControlFlowElement lastTypeCaseNoMatch(TypeCase tc, MatchingCompletion c) {
result = tc.getTypeAccess() and
not c.isMatch() and
c.isValidFor(result)
private ControlFlowElement lastTypeCaseNoMatch(TypeCase tc, Completion c) {
c.isValidFor(result) and
(
result = tc.getTypeAccess() and
c = any(MatchingCompletion mc | not mc.isMatch())
or
result = last(tc.getCondition(), _) and
c instanceof FalseCompletion
)
}
private ControlFlowElement lastRecursivePatternCaseNoMatch(
RecursivePatternCase rpc, Completion c
) {
c.isValidFor(result) and
(
result = rpc.getTypeAccess() and
c = any(MatchingCompletion mc | not mc.isMatch())
or
result = last(rpc.getCondition(), _) and
c instanceof FalseCompletion
)
}
pragma[nomagic]
@@ -1290,6 +1323,8 @@ module ControlFlow {
result = last(cs.(TypeCase).getStmt(), c)
or
result = last(cs.(ConstCase).getStmt(), c)
or
result = last(cs.(RecursivePatternCase).getStmt(), c)
}
pragma[nomagic]
@@ -1302,6 +1337,13 @@ module ControlFlow {
result = last(tc.getVariableDeclExpr(), c)
}
pragma[nomagic]
private ControlFlowElement lastRecursivePatternCaseVariableDeclExpr(
RecursivePatternCase tc, Completion c
) {
result = last(tc.getVariableDeclExpr(), c)
}
pragma[nomagic]
private ControlFlowElement lastLoopStmtCondition(LoopStmt ls, Completion c) {
result = last(ls.getCondition(), c)
@@ -1712,6 +1754,75 @@ module ControlFlow {
result = first(tc.getStmt())
)
or
exists(RecursivePatternCase tc |
cfe = tc and
result = tc.getTypeAccess() and
c instanceof SimpleCompletion
or
// Preorder: From the case stmt:
not exists(tc.getTypeAccess()) and
cfe = tc and
result = first(tc.getRecursivePattern()) and
c instanceof SimpleCompletion
or
// Flow from type test (if exists) to recursive pattern
cfe = tc.getTypeAccess() and
result = first(tc.getRecursivePattern()) and
c.isValidFor(cfe) and
c = any(MatchingCompletion mc | mc.isMatch())
or
// Flow to the next case
cfe = lastCaseNodeFailure(tc, c) and
exists(SwitchStmt ss2, int i | tc = ss2.getCase(i) | result = first(ss2.getCase(i + 1)))
or
cfe = last(tc.getRecursivePattern(), _) and
c.isValidFor(cfe) and
c = any(MatchingCompletion mc |
if mc.isMatch()
then
if exists(tc.getVariableDeclExpr())
then
// Flow from type test to first element of variable declaration
result = first(tc.getVariableDeclExpr())
else
if exists(tc.getCondition())
then
// Flow from type test to first element of condition
result = first(tc.getCondition())
else
// Flow from type test to first element of statement
result = first(tc.getStmt())
else
// Flow from type test to first element of next case
exists(SwitchStmt ss, int i | tc = ss.getCase(i) |
result = first(ss.getCase(i + 1))
)
)
or
cfe = lastRecursivePatternCaseVariableDeclExpr(tc, c) and
if exists(tc.getCondition())
then
// Flow from variable declaration to first element of condition
result = first(tc.getCondition())
else
// Flow from variable declaration to first element of statement
result = first(tc.getStmt())
or
cfe = lastTypeCaseVariableDeclExpr(tc, c) and
if exists(tc.getCondition())
then
// Flow from variable declaration to first element of condition
result = first(tc.getCondition())
else
// Flow from variable declaration to first element of statement
result = first(tc.getStmt())
or
// Flow from condition to first element of statement
cfe = lastCaseCondition(tc, c) and
c instanceof TrueCompletion and
result = first(tc.getStmt())
)
or
exists(LoopStmt ls |
// Flow from last element of condition to first element of loop body
cfe = lastLoopStmtCondition(ls, c) and
@@ -1954,6 +2065,28 @@ module ControlFlow {
c instanceof NormalCompletion
)
)
or
switchExprSucc(_, cfe, result, c)
}
/** Ways to leave a CaseStmt in the failure case. */
ControlFlowElement lastCaseNodeFailure(CaseStmt cfe, Completion c) {
c.isValidFor(result) and
(
c = any(MatchingCompletion m | not m.isMatch()) and
(
result = last(cfe.(ConstCase).getExpr(), _)
or
result = cfe.(RecursivePatternCase).getTypeAccess()
or
result = last(cfe.(RecursivePatternCase).getRecursivePattern(), c)
or
result = cfe.(TypeCase).getTypeAccess()
)
or
c instanceof FalseCompletion and
result = last(cfe.getCondition(), c)
)
}
/**
@@ -1998,6 +2131,60 @@ module ControlFlow {
cfe = last(result.getBody(), c) and
not c instanceof GotoCompletion
}
predicate switchExprSucc(
SwitchExpr expr, ControlFlowElement a, ControlFlowElement b, Completion c
) {
a = expr and b = first(expr.getExpr()) and c instanceof SimpleCompletion
or
// Go to the first case
a = last(expr.getExpr(), _) and b = first(expr.getCase(0)) and c instanceof SimpleCompletion
or
exists(SwitchCaseExpr case, int n | case = expr.getCase(n) |
// Go to the pattern
a = case and b = first(case.getPattern()) and c instanceof SimpleCompletion
or
// Pattern goes to result or condition
a = last(case.getPattern(), _) and
c = any(MatchingCompletion m | m.isMatch()) and
(
if exists(case.getCondition())
then b = first(case.getCondition())
else b = first(case.getResult())
)
or
a = last(case.getCondition(), _) and
b = first(case.getResult()) and
c.(TrueCompletion).isValidFor(case.getCondition())
or
a = last(case.getCondition(), _) and
b = expr.getCase(n + 1) and
c.(FalseCompletion).isValidFor(case.getCondition())
or
a = last(case.getPattern(), _) and
b = expr.getCase(n + 1) and
c = any(MatchingCompletion m | not m.isMatch())
)
}
ControlFlowElement lastSwitchExpr(SwitchExpr e, Completion c) {
result = last(e.getCase(_).getResult(), c)
or
exists(SwitchCaseExpr case, int i |
case = e.getCase(i) and
not e.getCase(i).matchesAll() and
not exists(e.getCase(i + 1))
|
(
result = case.getPattern() or
result = last(case.getCondition(), _)
) and
c
.(ThrowCompletion)
.getExceptionClass()
.hasQualifiedName("System.InvalidOperationException")
)
}
}
import Successor

View File

@@ -328,6 +328,8 @@ private predicate inBooleanContext(Expr e, boolean isBooleanCompletionForParent)
or
exists(CaseStmt cs | cs.getCondition() = e | isBooleanCompletionForParent = false)
or
exists(SwitchCaseExpr sce | sce.getCondition() = e | isBooleanCompletionForParent = false)
or
exists(SpecificCatchClause scc | scc.getFilterClause() = e | isBooleanCompletionForParent = false)
or
exists(LogicalNotExpr lne | lne.getAnOperand() = e |
@@ -414,6 +416,10 @@ predicate switchMatching(SwitchStmt ss, CaseStmt cs, ControlFlowElement cfe) {
cfe = cs.(ConstCase).getExpr()
or
cfe = cs.(TypeCase).getTypeAccess() // use type access to represent the type test
or
cfe = cs.(RecursivePatternCase).getTypeAccess() // use type access to represent the type test
or
cfe = cs.(RecursivePatternCase).getRecursivePattern() // a recursive pattern match
)
}

View File

@@ -251,7 +251,8 @@ class UncheckedExpr extends Expr, @unchecked_expr {
/**
* An `is` expression.
* Either an `is` type expression (`IsTypeExpr`) or an `is` constant expression (`IsConstantExpr`).
* Either an `is` type expression (`IsTypeExpr`), an `is` constant expression (`IsConstantExpr`),
* or an `is` recursive pattern expression (`IsPatternExpr`).
*/
class IsExpr extends Expr, @is_expr {
/**
@@ -262,9 +263,7 @@ class IsExpr extends Expr, @is_expr {
override string toString() { result = "... is ..." }
}
/**
* An `is` type expression, for example, `x is string` or `x is string s`.
*/
/** An `is` type expression, for example, `x is string` or `x is string s`. */
class IsTypeExpr extends IsExpr {
TypeAccess typeAccess;
@@ -283,19 +282,148 @@ class IsTypeExpr extends IsExpr {
TypeAccess getTypeAccess() { result = typeAccess }
}
/**
* An `is` pattern expression, for example `x is string s`.
*/
class IsPatternExpr extends IsTypeExpr {
/** An `is` pattern expression, for example `x is string s`. */
class IsPatternExpr extends IsExpr {
LocalVariableDeclExpr typeDecl;
IsPatternExpr() { typeDecl = this.getChild(2) }
IsPatternExpr() { typeDecl = this.getChild(2) and not this instanceof IsRecursivePatternExpr }
/**
* Gets the local variable declaration in this `is` pattern expression.
* For example `string s` in `x is string s`.
*/
LocalVariableDeclExpr getVariableDeclExpr() { result = typeDecl }
/**
* Gets the type being accessed in this `is` expression, for example `string`
* in `x is string`.
*/
Type getCheckedType() { result = getTypeAccess().getTarget() }
/**
* Gets the type access in this `is` expression, for example `string` in
* `x is string`.
*/
TypeAccess getTypeAccess() { result = this.getChild(1) }
}
/** An `is` recursive pattern expression, for example `x is string { Length: 5 } s`. */
class IsRecursivePatternExpr extends IsExpr {
RecursivePatternExpr recursivePattern;
IsRecursivePatternExpr() { recursivePattern = this.getChild(4) }
override string toString() { result = "... is { ... }" }
/**
* Gets the local variable declaration in this `is` pattern expression, if any.
* For example `s` in `x is string { Length: 0 } s`.
*/
LocalVariableDeclExpr getVariableDeclExpr() { result = this.getChild(2) }
/**
* Gets the recursive pattern of this `is` pattern expression. For example,
* `{ Length: 5 }` in `x is string { Length: 5 } s`.
*/
RecursivePatternExpr getRecursivePattern() { result = recursivePattern }
}
/**
* A recursive pattern expression, for example `string { Length: 5 } s`
*/
class RecursivePatternExpr extends Expr, @recursive_pattern_expr {
override string toString() { result = "{ ... }" }
/**
* Gets the position patterns of this recursive pattern, if any.
* For example, `(1,_)`.
*/
PositionalPatternExpr getPositionalPatterns() { result = this.getChild(2) }
/**
* Gets the property patterns of this recursive pattern, if any.
* For example,
* `{ Length: 5 }` in `o is string { Length: 5 } s`
*/
PropertyPatternExpr getPropertyPatterns() { result = this.getChild(3) }
/**
* Gets the type access of this recursive pattern, if any.
* For example, `string` in `string { Length: 5 }`
*/
TypeAccess getTypeAccess() { result = this.getChild(1) }
/**
* Gets the local variable declaration of this recursive pattern, if any.
* For example, `s` in `string { Length: 5 } s`.
*/
LocalVariableDeclExpr getVariableDeclExpr() { result = this.getChild(0) }
}
/** A property pattern. For example, `{Length: 5}`. */
class PropertyPatternExpr extends Expr, @property_pattern_expr {
override string toString() { result = "{ ... }" }
/** Gets the `n`th pattern. */
Expr getPattern(int n) { result = this.getChild(n) }
}
/** A property pattern. For example, `(int x, int y)`. */
class PositionalPatternExpr extends Expr, @positional_pattern_expr {
override string toString() { result = "( ... )" }
/** Gets the `n`th pattern. */
Expr getPattern(int n) { result = this.getChild(n) }
}
/**
* A `switch` expression, for example
* ```
* (a,b) switch {
* (false, false) => true,
* _ => false
* };
* ```
*/
class SwitchExpr extends Expr, @switch_expr {
override string toString() { result = "... switch { ... }" }
/** Gets the expression being switched. For example `x` in `x switch { ... }`. */
Expr getExpr() { result = this.getChild(-1) }
/** Gets the `n`th case of this switch expression. */
SwitchCaseExpr getCase(int n) { result = this.getChild(n) }
}
/** An arm of a switch expression, for example `(false, false) => true`. */
class SwitchCaseExpr extends Expr, @switch_case_expr {
override string toString() { result = "... => ..." }
/**
* Gets the pattern or matched expression in a switch arm, for example `(false, false)` in
* `(false, false) => true`.
*/
Expr getPattern() { result = this.getChild(0) }
/**
* Gets the `when` expression in a switch arm, if any.
* For example `s.Length<10` in `string s when s.Length<10 => s`.
*/
Expr getCondition() { result = this.getChild(1) }
/**
* Gets the result of a switch arm, for example `true` in
* `(false, false) => true`.
*/
Expr getResult() { result = this.getChild(2) }
/** Holds if this case expression matches all expressions. */
predicate matchesAll() {
// Note: There may be other cases as well.
// For example `(1,2) switch { (int x, int y) => x+y }`
// would match all cases due to the type of the expression.
getPattern() instanceof DiscardExpr
}
}
/**

View File

@@ -975,8 +975,14 @@ case @expr.kind of
| 109 = @local_function_invocation_expr
| 110 = @ref_expr
| 111 = @discard_expr
/* C# 8.0 */
| 112 = @range_expr
| 113 = @index_expr
| 114 = @switch_expr
| 115 = @recursive_pattern_expr
| 116 = @property_pattern_expr
| 117 = @positional_pattern_expr
| 118 = @switch_case_expr
;
@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;

View File

@@ -1240,8 +1240,10 @@
| Switch.cs:46:9:52:9 | switch (...) {...} | Switch.cs:46:9:52:9 | switch (...) {...} |
| Switch.cs:46:17:46:17 | access to parameter o | Switch.cs:46:17:46:17 | access to parameter o |
| Switch.cs:48:13:48:23 | case Int32: | Switch.cs:48:13:48:23 | case Int32: |
| Switch.cs:48:22:48:22 | _ | Switch.cs:48:22:48:22 | _ |
| Switch.cs:49:17:49:22 | break; | Switch.cs:49:17:49:22 | break; |
| Switch.cs:50:13:50:39 | case Boolean: | Switch.cs:50:13:50:39 | case Boolean: |
| Switch.cs:50:23:50:23 | _ | Switch.cs:50:23:50:23 | _ |
| Switch.cs:50:30:50:30 | access to parameter o | Switch.cs:50:30:50:30 | access to parameter o |
| Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:30:50:30 | access to parameter o |
| Switch.cs:50:35:50:38 | null | Switch.cs:50:35:50:38 | null |
@@ -1262,6 +1264,7 @@
| Switch.cs:68:17:68:25 | (...) ... | Switch.cs:68:25:68:25 | access to parameter s |
| Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:25:68:25 | access to parameter s |
| Switch.cs:70:13:70:24 | case Int32: | Switch.cs:70:13:70:24 | case Int32: |
| Switch.cs:70:22:70:22 | _ | Switch.cs:70:22:70:22 | _ |
| Switch.cs:71:15:71:20 | break; | Switch.cs:71:15:71:20 | break; |
| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:13:72:21 | case ...: |
| Switch.cs:72:18:72:19 | "" | Switch.cs:72:18:72:19 | "" |
@@ -1288,6 +1291,7 @@
| Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:93:9:97:9 | switch (...) {...} |
| Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:93:17:93:17 | access to parameter o |
| Switch.cs:95:13:95:24 | case Int32: | Switch.cs:95:13:95:24 | case Int32: |
| Switch.cs:95:22:95:22 | _ | Switch.cs:95:22:95:22 | _ |
| Switch.cs:96:15:96:26 | return ...; | Switch.cs:96:22:96:25 | true |
| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true |
| Switch.cs:98:9:98:21 | return ...; | Switch.cs:98:16:98:20 | false |

View File

@@ -1553,6 +1553,7 @@
| Switch.cs:25:35:25:35 | access to local variable s | Switch.cs:25:35:25:35 | access to local variable s | normal |
| Switch.cs:26:17:26:23 | return ...; | Switch.cs:26:17:26:23 | return ...; | return |
| Switch.cs:27:13:27:39 | case Double d: | Switch.cs:27:18:27:23 | access to type Double | no-match |
| Switch.cs:27:13:27:39 | case Double d: | Switch.cs:27:32:27:38 | call to method Throw | false/false |
| Switch.cs:27:13:27:39 | case Double d: | Switch.cs:27:32:27:38 | call to method Throw | throw(Exception) |
| Switch.cs:27:13:27:39 | case Double d: | Switch.cs:28:17:28:21 | Label: | normal |
| Switch.cs:27:18:27:25 | Double d | Switch.cs:27:18:27:25 | Double d | normal |
@@ -1579,10 +1580,12 @@
| Switch.cs:46:17:46:17 | access to parameter o | Switch.cs:46:17:46:17 | access to parameter o | normal |
| Switch.cs:48:13:48:23 | case Int32: | Switch.cs:48:18:48:20 | access to type Int32 | no-match |
| Switch.cs:48:13:48:23 | case Int32: | Switch.cs:49:17:49:22 | break; | break |
| Switch.cs:48:22:48:22 | _ | Switch.cs:48:22:48:22 | _ | normal |
| Switch.cs:49:17:49:22 | break; | Switch.cs:49:17:49:22 | break; | break |
| Switch.cs:50:13:50:39 | case Boolean: | Switch.cs:50:18:50:21 | access to type Boolean | no-match |
| Switch.cs:50:13:50:39 | case Boolean: | Switch.cs:50:30:50:38 | ... != ... | false/false |
| Switch.cs:50:13:50:39 | case Boolean: | Switch.cs:51:17:51:22 | break; | break |
| Switch.cs:50:23:50:23 | _ | Switch.cs:50:23:50:23 | _ | normal |
| Switch.cs:50:30:50:30 | access to parameter o | Switch.cs:50:30:50:30 | access to parameter o | normal |
| Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:30:50:38 | ... != ... | false/false |
| Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:30:50:38 | ... != ... | true/true |
@@ -1612,6 +1615,7 @@
| Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:25:68:25 | access to parameter s | normal |
| Switch.cs:70:13:70:24 | case Int32: | Switch.cs:70:18:70:20 | access to type Int32 | no-match |
| Switch.cs:70:13:70:24 | case Int32: | Switch.cs:71:15:71:20 | break; | break |
| Switch.cs:70:22:70:22 | _ | Switch.cs:70:22:70:22 | _ | normal |
| Switch.cs:71:15:71:20 | break; | Switch.cs:71:15:71:20 | break; | break |
| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:18:72:19 | "" | no-match |
| Switch.cs:72:13:72:21 | case ...: | Switch.cs:73:15:73:20 | break; | break |
@@ -1655,6 +1659,7 @@
| Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:93:17:93:17 | access to parameter o | normal |
| Switch.cs:95:13:95:24 | case Int32: | Switch.cs:95:18:95:20 | access to type Int32 | no-match |
| Switch.cs:95:13:95:24 | case Int32: | Switch.cs:96:15:96:26 | return ...; | return |
| Switch.cs:95:22:95:22 | _ | Switch.cs:95:22:95:22 | _ | normal |
| Switch.cs:96:15:96:26 | return ...; | Switch.cs:96:15:96:26 | return ...; | return |
| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true | normal |
| Switch.cs:98:9:98:21 | return ...; | Switch.cs:98:9:98:21 | return ...; | return |

View File

@@ -6,3 +6,4 @@
| CSharp7.cs:224:17:224:17 | _ | Double |
| CSharp7.cs:224:28:224:28 | _ | Boolean |
| CSharp7.cs:225:10:225:10 | _ | Int32 |
| CSharp7.cs:267:25:267:25 | _ | null |

View File

@@ -0,0 +1,66 @@
| patterns.cs:5:10:5:19 | enter IsPatterns | patterns.cs:6:5:30:5 | {...} | semmle.label | successor |
| patterns.cs:6:5:30:5 | {...} | patterns.cs:7:9:7:42 | ... ...; | semmle.label | successor |
| patterns.cs:7:9:7:42 | ... ...; | patterns.cs:7:20:7:41 | object creation of type MyStruct | semmle.label | successor |
| patterns.cs:7:16:7:41 | Object o = ... | patterns.cs:9:9:11:9 | if (...) ... | semmle.label | successor |
| patterns.cs:7:20:7:41 | (...) ... | patterns.cs:7:16:7:41 | Object o = ... | semmle.label | successor |
| patterns.cs:7:20:7:41 | object creation of type MyStruct | patterns.cs:7:39:7:39 | 2 | semmle.label | successor |
| patterns.cs:7:33:7:41 | { ..., ... } | patterns.cs:7:20:7:41 | (...) ... | semmle.label | successor |
| patterns.cs:7:35:7:39 | ... = ... | patterns.cs:7:33:7:41 | { ..., ... } | semmle.label | successor |
| patterns.cs:7:39:7:39 | 2 | patterns.cs:7:35:7:39 | ... = ... | semmle.label | successor |
| patterns.cs:9:9:11:9 | if (...) ... | patterns.cs:9:13:9:13 | access to local variable o | semmle.label | successor |
| patterns.cs:9:13:9:13 | access to local variable o | patterns.cs:9:18:9:29 | MyStruct ms1 | semmle.label | successor |
| patterns.cs:9:13:9:29 | ... is ... | patterns.cs:10:9:11:9 | {...} | semmle.label | true |
| patterns.cs:9:13:9:29 | ... is ... | patterns.cs:13:9:15:9 | if (...) ... | semmle.label | false |
| patterns.cs:9:18:9:29 | MyStruct ms1 | patterns.cs:9:13:9:29 | ... is ... | semmle.label | successor |
| patterns.cs:10:9:11:9 | {...} | patterns.cs:13:9:15:9 | if (...) ... | semmle.label | successor |
| patterns.cs:13:9:15:9 | if (...) ... | patterns.cs:13:13:13:56 | ... && ... | semmle.label | successor |
| patterns.cs:13:13:13:13 | access to local variable o | patterns.cs:13:18:13:40 | MyStruct s | semmle.label | successor |
| patterns.cs:13:13:13:40 | ... is { ... } | patterns.cs:13:45:13:45 | access to local variable x | semmle.label | true |
| patterns.cs:13:13:13:40 | ... is { ... } | patterns.cs:17:9:19:9 | if (...) ... | semmle.label | false |
| patterns.cs:13:13:13:47 | ... && ... | patterns.cs:13:13:13:13 | access to local variable o | semmle.label | successor |
| patterns.cs:13:13:13:56 | ... && ... | patterns.cs:13:13:13:47 | ... && ... | semmle.label | successor |
| patterns.cs:13:18:13:40 | MyStruct s | patterns.cs:13:32:13:36 | Int32 x | semmle.label | successor |
| patterns.cs:13:18:13:40 | { ... } | patterns.cs:13:13:13:40 | ... is { ... } | semmle.label | successor |
| patterns.cs:13:27:13:38 | { ... } | patterns.cs:13:18:13:40 | { ... } | semmle.label | successor |
| patterns.cs:13:32:13:36 | Int32 x | patterns.cs:13:27:13:38 | { ... } | semmle.label | successor |
| patterns.cs:13:45:13:45 | access to local variable x | patterns.cs:13:47:13:47 | 4 | semmle.label | successor |
| patterns.cs:13:45:13:47 | ... < ... | patterns.cs:13:52:13:52 | access to local variable s | semmle.label | true |
| patterns.cs:13:45:13:47 | ... < ... | patterns.cs:17:9:19:9 | if (...) ... | semmle.label | false |
| patterns.cs:13:47:13:47 | 4 | patterns.cs:13:45:13:47 | ... < ... | semmle.label | successor |
| patterns.cs:13:52:13:52 | access to local variable s | patterns.cs:13:52:13:54 | access to property Y | semmle.label | successor |
| patterns.cs:13:52:13:54 | access to property Y | patterns.cs:13:56:13:56 | 2 | semmle.label | successor |
| patterns.cs:13:52:13:56 | ... < ... | patterns.cs:14:9:15:9 | {...} | semmle.label | true |
| patterns.cs:13:52:13:56 | ... < ... | patterns.cs:17:9:19:9 | if (...) ... | semmle.label | false |
| patterns.cs:13:56:13:56 | 2 | patterns.cs:13:52:13:56 | ... < ... | semmle.label | successor |
| patterns.cs:14:9:15:9 | {...} | patterns.cs:17:9:19:9 | if (...) ... | semmle.label | successor |
| patterns.cs:17:9:19:9 | if (...) ... | patterns.cs:17:13:17:13 | access to local variable o | semmle.label | successor |
| patterns.cs:17:13:17:13 | access to local variable o | patterns.cs:17:18:17:21 | Object p | semmle.label | successor |
| patterns.cs:17:13:17:21 | ... is { ... } | patterns.cs:18:9:19:9 | {...} | semmle.label | true |
| patterns.cs:17:13:17:21 | ... is { ... } | patterns.cs:22:9:24:9 | if (...) ... | semmle.label | false |
| patterns.cs:17:18:17:19 | { ... } | patterns.cs:17:18:17:21 | { ... } | semmle.label | successor |
| patterns.cs:17:18:17:21 | Object p | patterns.cs:17:18:17:19 | { ... } | semmle.label | successor |
| patterns.cs:17:18:17:21 | { ... } | patterns.cs:17:13:17:21 | ... is { ... } | semmle.label | successor |
| patterns.cs:18:9:19:9 | {...} | patterns.cs:22:9:24:9 | if (...) ... | semmle.label | successor |
| patterns.cs:22:9:24:9 | if (...) ... | patterns.cs:22:13:22:13 | access to local variable o | semmle.label | successor |
| patterns.cs:22:13:22:13 | access to local variable o | patterns.cs:22:31:22:32 | 12 | semmle.label | successor |
| patterns.cs:22:13:22:53 | ... is { ... } | patterns.cs:23:9:24:9 | {...} | semmle.label | true |
| patterns.cs:22:13:22:53 | ... is { ... } | patterns.cs:27:9:29:9 | if (...) ... | semmle.label | false |
| patterns.cs:22:18:22:53 | { ... } | patterns.cs:22:13:22:53 | ... is { ... } | semmle.label | successor |
| patterns.cs:22:27:22:53 | { ... } | patterns.cs:22:18:22:53 | { ... } | semmle.label | successor |
| patterns.cs:22:31:22:32 | 12 | patterns.cs:22:42:22:49 | Int32 subX | semmle.label | successor |
| patterns.cs:22:38:22:51 | { ... } | patterns.cs:22:27:22:53 | { ... } | semmle.label | successor |
| patterns.cs:22:38:22:51 | { ... } | patterns.cs:22:38:22:51 | { ... } | semmle.label | successor |
| patterns.cs:22:42:22:49 | Int32 subX | patterns.cs:22:38:22:51 | { ... } | semmle.label | successor |
| patterns.cs:23:9:24:9 | {...} | patterns.cs:27:9:29:9 | if (...) ... | semmle.label | successor |
| patterns.cs:27:9:29:9 | if (...) ... | patterns.cs:27:13:27:13 | access to local variable o | semmle.label | successor |
| patterns.cs:27:13:27:13 | access to local variable o | patterns.cs:27:31:27:32 | 12 | semmle.label | successor |
| patterns.cs:27:13:27:58 | ... is { ... } | patterns.cs:5:10:5:19 | exit IsPatterns | semmle.label | false |
| patterns.cs:27:13:27:58 | ... is { ... } | patterns.cs:28:9:29:9 | {...} | semmle.label | true |
| patterns.cs:27:18:27:58 | { ... } | patterns.cs:27:13:27:58 | ... is { ... } | semmle.label | successor |
| patterns.cs:27:27:27:58 | { ... } | patterns.cs:27:18:27:58 | { ... } | semmle.label | successor |
| patterns.cs:27:31:27:32 | 12 | patterns.cs:27:38:27:56 | MyStruct ms | semmle.label | successor |
| patterns.cs:27:38:27:56 | MyStruct ms | patterns.cs:27:51:27:51 | _ | semmle.label | successor |
| patterns.cs:27:38:27:56 | { ... } | patterns.cs:27:27:27:58 | { ... } | semmle.label | successor |
| patterns.cs:27:47:27:53 | { ... } | patterns.cs:27:38:27:56 | { ... } | semmle.label | successor |
| patterns.cs:27:51:27:51 | _ | patterns.cs:27:47:27:53 | { ... } | semmle.label | successor |
| patterns.cs:28:9:29:9 | {...} | patterns.cs:5:10:5:19 | exit IsPatterns | semmle.label | successor |

View File

@@ -0,0 +1,10 @@
import csharp
query predicate edges(ControlFlow::Node a, ControlFlow::Node b, string label, string value) {
exists(ControlFlow::SuccessorType t |
a.getEnclosingCallable().getName() = "IsPatterns" and
b = a.getASuccessorByType(t) and
label = "semmle.label" and
value = t.toString()
)
}

View File

@@ -0,0 +1,166 @@
using System;
class Patterns
{
void IsPatterns()
{
object o = new MyStruct { X = 2 };
if (o is MyStruct ms1)
{
}
if (o is MyStruct { X: int x } s && x<4 && s.Y<2)
{
}
if (o is {} p)
{
}
// A sub-pattern match
if (o is MyStruct {X: 12, S: {X: var subX } })
{
}
// A sub-pattern match
if (o is MyStruct {X: 12, S: MyStruct {X: _ } ms })
{
}
}
void SwitchStatements()
{
var s = new MyStruct { X = 0 };
switch (s)
{
case MyStruct ms1 when ms1.X == 10:
Console.WriteLine("Hit the breakpoint");
break;
case MyStruct ms2 when ms2.X < 10:
Console.WriteLine("Missed the breakpoint");
break;
}
switch (s)
{
case MyStruct { X: int x } when x > 2:
Console.WriteLine(x);
break;
case MyStruct { X: 10 } ms:
Console.WriteLine("Hit the breakpoint");
break;
case { X: int x2 } when x2 > 2:
Console.WriteLine(x2);
break;
case (1, 2):
break;
case var (x, y):
break;
default:
break;
}
switch (s)
{
case MyStruct { X: int x } when x > 2:
Console.WriteLine(x);
break;
case MyStruct { X: 10 } ms when s.X==0:
Console.WriteLine("Hit the breakpoint");
break;
}
switch (new object())
{
case (int x, float y) when x<y:
break;
case ():
break;
case {}:
break;
}
switch(1,2)
{
case (1, 2): break;
}
switch((1,2))
{
case (1, var x): break;
case (2, _): break;
}
}
void Expressions(int x)
{
var size = x switch {
int y when y > 10 => "large",
_ => "small"
};
int x0 = 0, y0 = 0;
// Potential fall through
var (x1, y1) = (x0, y0) switch
{
(0,1) => (1,0),
(1,0) => (0,1)
};
// No fall through
(x1, y1) = (x0, y0) switch
{
(0,var y2) => (y2, 0),
(var x2, 0) => (0, x2),
(var x2, var y2) => (0, 0)
};
}
void Expressions2()
{
var s = new MyStruct { X = 0 };
var r = s switch
{
MyStruct { X: int x } when x > 2 => 0,
MyStruct { X: 10 } ms => 1,
(1, 2) => 2,
var (x, _) => 3
};
try
{
r = 0 switch
{
1 => throw new ArgumentException(),
2 => 3,
object y when y is {} => 4
};
}
catch(InvalidOperationException ex)
{
Console.WriteLine("Invalid operation");
}
}
struct MyStruct
{
public int X;
public int Y => 10;
public MyStruct S => this;
public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
public void Deconstruct()
{
}
}
}

View File

@@ -0,0 +1,164 @@
switchExprs
| patterns.cs:100:20:103:9 | ... switch { ... } | patterns.cs:100:20:100:20 | access to parameter x |
| patterns.cs:108:24:112:9 | ... switch { ... } | patterns.cs:108:24:108:31 | (..., ...) |
| patterns.cs:115:20:120:9 | ... switch { ... } | patterns.cs:115:20:115:27 | (..., ...) |
| patterns.cs:126:17:132:9 | ... switch { ... } | patterns.cs:126:17:126:17 | access to local variable s |
| patterns.cs:136:17:141:13 | ... switch { ... } | patterns.cs:136:17:136:17 | 0 |
switchExprCases
| patterns.cs:101:13:101:40 | ... => ... | patterns.cs:101:13:101:17 | Int32 y | patterns.cs:101:34:101:40 | "large" |
| patterns.cs:102:13:102:24 | ... => ... | patterns.cs:102:13:102:13 | _ | patterns.cs:102:18:102:24 | "small" |
| patterns.cs:110:13:110:26 | ... => ... | patterns.cs:110:13:110:17 | { ... } | patterns.cs:110:22:110:26 | (..., ...) |
| patterns.cs:111:13:111:26 | ... => ... | patterns.cs:111:13:111:17 | { ... } | patterns.cs:111:22:111:26 | (..., ...) |
| patterns.cs:117:13:117:33 | ... => ... | patterns.cs:117:13:117:22 | { ... } | patterns.cs:117:27:117:33 | (..., ...) |
| patterns.cs:118:13:118:34 | ... => ... | patterns.cs:118:13:118:23 | { ... } | patterns.cs:118:28:118:34 | (..., ...) |
| patterns.cs:119:13:119:38 | ... => ... | patterns.cs:119:13:119:28 | { ... } | patterns.cs:119:33:119:38 | (..., ...) |
| patterns.cs:128:13:128:49 | ... => ... | patterns.cs:128:13:128:33 | { ... } | patterns.cs:128:49:128:49 | 0 |
| patterns.cs:129:13:129:38 | ... => ... | patterns.cs:129:13:129:33 | { ... } | patterns.cs:129:38:129:38 | 1 |
| patterns.cs:130:13:130:23 | ... => ... | patterns.cs:130:13:130:18 | { ... } | patterns.cs:130:23:130:23 | 2 |
| patterns.cs:131:13:131:27 | ... => ... | patterns.cs:131:13:131:22 | (..., ...) | patterns.cs:131:27:131:27 | 3 |
| patterns.cs:138:17:138:50 | ... => ... | patterns.cs:138:17:138:17 | 1 | patterns.cs:138:22:138:50 | throw ... |
| patterns.cs:139:17:139:22 | ... => ... | patterns.cs:139:17:139:17 | 2 | patterns.cs:139:22:139:22 | 3 |
| patterns.cs:140:17:140:42 | ... => ... | patterns.cs:140:17:140:24 | Object y | patterns.cs:140:42:140:42 | 4 |
switchFilters
| patterns.cs:101:13:101:40 | ... => ... | patterns.cs:101:24:101:29 | ... > ... |
| patterns.cs:128:13:128:49 | ... => ... | patterns.cs:128:40:128:44 | ... > ... |
| patterns.cs:140:17:140:42 | ... => ... | patterns.cs:140:31:140:37 | ... is { ... } |
propertyPatterns
| patterns.cs:13:27:13:38 | { ... } |
| patterns.cs:17:18:17:19 | { ... } |
| patterns.cs:22:27:22:53 | { ... } |
| patterns.cs:22:38:22:51 | { ... } |
| patterns.cs:27:27:27:58 | { ... } |
| patterns.cs:27:47:27:53 | { ... } |
| patterns.cs:48:27:48:38 | { ... } |
| patterns.cs:51:27:51:35 | { ... } |
| patterns.cs:54:18:54:30 | { ... } |
| patterns.cs:67:27:67:38 | { ... } |
| patterns.cs:70:27:70:35 | { ... } |
| patterns.cs:82:18:82:19 | { ... } |
| patterns.cs:128:22:128:33 | { ... } |
| patterns.cs:129:22:129:30 | { ... } |
| patterns.cs:140:36:140:37 | { ... } |
propertyPatternChild
| patterns.cs:13:27:13:38 | { ... } | 0 | patterns.cs:13:32:13:36 | Int32 x |
| patterns.cs:22:27:22:53 | { ... } | 0 | patterns.cs:22:31:22:32 | 12 |
| patterns.cs:22:27:22:53 | { ... } | 1 | patterns.cs:22:38:22:51 | { ... } |
| patterns.cs:22:38:22:51 | { ... } | 0 | patterns.cs:22:42:22:49 | Int32 subX |
| patterns.cs:27:27:27:58 | { ... } | 0 | patterns.cs:27:31:27:32 | 12 |
| patterns.cs:27:27:27:58 | { ... } | 1 | patterns.cs:27:38:27:56 | { ... } |
| patterns.cs:27:47:27:53 | { ... } | 0 | patterns.cs:27:51:27:51 | _ |
| patterns.cs:48:27:48:38 | { ... } | 0 | patterns.cs:48:32:48:36 | Int32 x |
| patterns.cs:51:27:51:35 | { ... } | 0 | patterns.cs:51:32:51:33 | 10 |
| patterns.cs:54:18:54:30 | { ... } | 0 | patterns.cs:54:23:54:28 | Int32 x2 |
| patterns.cs:67:27:67:38 | { ... } | 0 | patterns.cs:67:32:67:36 | Int32 x |
| patterns.cs:70:27:70:35 | { ... } | 0 | patterns.cs:70:32:70:33 | 10 |
| patterns.cs:128:22:128:33 | { ... } | 0 | patterns.cs:128:27:128:31 | Int32 x |
| patterns.cs:129:22:129:30 | { ... } | 0 | patterns.cs:129:27:129:28 | 10 |
positionalPatterns
| patterns.cs:57:18:57:23 | ( ... ) | patterns.cs:57:18:57:23 | { ... } | 0 | patterns.cs:57:19:57:19 | 1 |
| patterns.cs:57:18:57:23 | ( ... ) | patterns.cs:57:18:57:23 | { ... } | 1 | patterns.cs:57:22:57:22 | 2 |
| patterns.cs:78:18:78:33 | ( ... ) | patterns.cs:78:18:78:33 | { ... } | 0 | patterns.cs:78:19:78:23 | Int32 x |
| patterns.cs:78:18:78:33 | ( ... ) | patterns.cs:78:18:78:33 | { ... } | 1 | patterns.cs:78:26:78:32 | Single y |
| patterns.cs:88:18:88:23 | ( ... ) | patterns.cs:88:18:88:23 | { ... } | 0 | patterns.cs:88:19:88:19 | 1 |
| patterns.cs:88:18:88:23 | ( ... ) | patterns.cs:88:18:88:23 | { ... } | 1 | patterns.cs:88:22:88:22 | 2 |
| patterns.cs:93:18:93:27 | ( ... ) | patterns.cs:93:18:93:27 | { ... } | 0 | patterns.cs:93:19:93:19 | 1 |
| patterns.cs:93:18:93:27 | ( ... ) | patterns.cs:93:18:93:27 | { ... } | 1 | patterns.cs:93:22:93:26 | Int32 x |
| patterns.cs:94:18:94:23 | ( ... ) | patterns.cs:94:18:94:23 | { ... } | 0 | patterns.cs:94:19:94:19 | 2 |
| patterns.cs:94:18:94:23 | ( ... ) | patterns.cs:94:18:94:23 | { ... } | 1 | patterns.cs:94:22:94:22 | _ |
| patterns.cs:110:13:110:17 | ( ... ) | patterns.cs:110:13:110:17 | { ... } | 0 | patterns.cs:110:14:110:14 | 0 |
| patterns.cs:110:13:110:17 | ( ... ) | patterns.cs:110:13:110:17 | { ... } | 1 | patterns.cs:110:16:110:16 | 1 |
| patterns.cs:111:13:111:17 | ( ... ) | patterns.cs:111:13:111:17 | { ... } | 0 | patterns.cs:111:14:111:14 | 1 |
| patterns.cs:111:13:111:17 | ( ... ) | patterns.cs:111:13:111:17 | { ... } | 1 | patterns.cs:111:16:111:16 | 0 |
| patterns.cs:117:13:117:22 | ( ... ) | patterns.cs:117:13:117:22 | { ... } | 0 | patterns.cs:117:14:117:14 | 0 |
| patterns.cs:117:13:117:22 | ( ... ) | patterns.cs:117:13:117:22 | { ... } | 1 | patterns.cs:117:16:117:21 | Int32 y2 |
| patterns.cs:118:13:118:23 | ( ... ) | patterns.cs:118:13:118:23 | { ... } | 0 | patterns.cs:118:14:118:19 | Int32 x2 |
| patterns.cs:118:13:118:23 | ( ... ) | patterns.cs:118:13:118:23 | { ... } | 1 | patterns.cs:118:22:118:22 | 0 |
| patterns.cs:119:13:119:28 | ( ... ) | patterns.cs:119:13:119:28 | { ... } | 0 | patterns.cs:119:14:119:19 | Int32 x2 |
| patterns.cs:119:13:119:28 | ( ... ) | patterns.cs:119:13:119:28 | { ... } | 1 | patterns.cs:119:22:119:27 | Int32 y2 |
| patterns.cs:130:13:130:18 | ( ... ) | patterns.cs:130:13:130:18 | { ... } | 0 | patterns.cs:130:14:130:14 | 1 |
| patterns.cs:130:13:130:18 | ( ... ) | patterns.cs:130:13:130:18 | { ... } | 1 | patterns.cs:130:17:130:17 | 2 |
caseStatements
| patterns.cs:38:13:38:47 | case MyStruct ms1: |
| patterns.cs:41:13:41:46 | case MyStruct ms2: |
| patterns.cs:48:13:48:50 | case { ... }: |
| patterns.cs:51:13:51:39 | case { ... }: |
| patterns.cs:54:13:54:43 | case { ... }: |
| patterns.cs:57:13:57:24 | case { ... }: |
| patterns.cs:59:13:59:28 | case ...: |
| patterns.cs:61:13:61:20 | default: |
| patterns.cs:67:13:67:50 | case { ... }: |
| patterns.cs:70:13:70:51 | case { ... }: |
| patterns.cs:78:13:78:43 | case { ... }: |
| patterns.cs:80:13:80:20 | case { ... }: |
| patterns.cs:82:13:82:20 | case { ... }: |
| patterns.cs:88:13:88:24 | case { ... }: |
| patterns.cs:93:13:93:28 | case { ... }: |
| patterns.cs:94:13:94:24 | case { ... }: |
recursivePatternCases
| patterns.cs:48:13:48:50 | case { ... }: | patterns.cs:48:18:48:38 | { ... } |
| patterns.cs:51:13:51:39 | case { ... }: | patterns.cs:51:18:51:38 | { ... } |
| patterns.cs:54:13:54:43 | case { ... }: | patterns.cs:54:18:54:30 | { ... } |
| patterns.cs:57:13:57:24 | case { ... }: | patterns.cs:57:18:57:23 | { ... } |
| patterns.cs:67:13:67:50 | case { ... }: | patterns.cs:67:18:67:38 | { ... } |
| patterns.cs:70:13:70:51 | case { ... }: | patterns.cs:70:18:70:38 | { ... } |
| patterns.cs:78:13:78:43 | case { ... }: | patterns.cs:78:18:78:33 | { ... } |
| patterns.cs:80:13:80:20 | case { ... }: | patterns.cs:80:18:80:19 | { ... } |
| patterns.cs:82:13:82:20 | case { ... }: | patterns.cs:82:18:82:19 | { ... } |
| patterns.cs:88:13:88:24 | case { ... }: | patterns.cs:88:18:88:23 | { ... } |
| patterns.cs:93:13:93:28 | case { ... }: | patterns.cs:93:18:93:27 | { ... } |
| patterns.cs:94:13:94:24 | case { ... }: | patterns.cs:94:18:94:23 | { ... } |
recursiveCasePatternDecl
| patterns.cs:51:13:51:39 | case { ... }: | patterns.cs:51:18:51:25 | access to type MyStruct | patterns.cs:51:18:51:38 | MyStruct ms |
| patterns.cs:70:13:70:51 | case { ... }: | patterns.cs:70:18:70:25 | access to type MyStruct | patterns.cs:70:18:70:38 | MyStruct ms |
recursivePatternDecl
| patterns.cs:27:38:27:56 | { ... } | patterns.cs:27:38:27:56 | MyStruct ms |
| patterns.cs:129:13:129:33 | { ... } | patterns.cs:129:13:129:33 | MyStruct ms |
recursivePatterns
| patterns.cs:13:18:13:40 | { ... } |
| patterns.cs:17:18:17:21 | { ... } |
| patterns.cs:22:18:22:53 | { ... } |
| patterns.cs:22:38:22:51 | { ... } |
| patterns.cs:27:18:27:58 | { ... } |
| patterns.cs:27:38:27:56 | { ... } |
| patterns.cs:48:18:48:38 | { ... } |
| patterns.cs:51:18:51:38 | { ... } |
| patterns.cs:54:18:54:30 | { ... } |
| patterns.cs:57:18:57:23 | { ... } |
| patterns.cs:67:18:67:38 | { ... } |
| patterns.cs:70:18:70:38 | { ... } |
| patterns.cs:78:18:78:33 | { ... } |
| patterns.cs:80:18:80:19 | { ... } |
| patterns.cs:82:18:82:19 | { ... } |
| patterns.cs:88:18:88:23 | { ... } |
| patterns.cs:93:18:93:27 | { ... } |
| patterns.cs:94:18:94:23 | { ... } |
| patterns.cs:110:13:110:17 | { ... } |
| patterns.cs:111:13:111:17 | { ... } |
| patterns.cs:117:13:117:22 | { ... } |
| patterns.cs:118:13:118:23 | { ... } |
| patterns.cs:119:13:119:28 | { ... } |
| patterns.cs:128:13:128:33 | { ... } |
| patterns.cs:129:13:129:33 | { ... } |
| patterns.cs:130:13:130:18 | { ... } |
| patterns.cs:140:36:140:37 | { ... } |
discards
| patterns.cs:27:51:27:51 | _ |
| patterns.cs:94:22:94:22 | _ |
| patterns.cs:102:13:102:13 | _ |
| patterns.cs:131:21:131:21 | _ |
isExprs
| patterns.cs:9:13:9:29 | ... is ... |
| patterns.cs:13:13:13:40 | ... is { ... } |
| patterns.cs:17:13:17:21 | ... is { ... } |
| patterns.cs:22:13:22:53 | ... is { ... } |
| patterns.cs:27:13:27:58 | ... is { ... } |
| patterns.cs:140:31:140:37 | ... is { ... } |
isRecursivePatternExpr
| patterns.cs:13:13:13:40 | ... is { ... } |
| patterns.cs:17:13:17:21 | ... is { ... } |
| patterns.cs:22:13:22:53 | ... is { ... } |
| patterns.cs:27:13:27:58 | ... is { ... } |
| patterns.cs:140:31:140:37 | ... is { ... } |
isRecursivePatternExprWithDecl
| patterns.cs:13:13:13:40 | ... is { ... } | patterns.cs:13:18:13:40 | MyStruct s |
| patterns.cs:17:13:17:21 | ... is { ... } | patterns.cs:17:18:17:21 | Object p |

View File

@@ -0,0 +1,50 @@
import csharp
query predicate switchExprs(SwitchExpr switch, Expr e) { e = switch.getExpr() }
query predicate switchExprCases(SwitchCaseExpr case, Expr pattern, Expr res) {
pattern = case.getPattern() and res = case.getResult()
}
query predicate switchFilters(SwitchCaseExpr case, Expr when) { when = case.getCondition() }
query predicate propertyPatterns(PropertyPatternExpr pp) { any() }
query predicate propertyPatternChild(PropertyPatternExpr pp, int n, Expr child) {
child = pp.getPattern(n)
}
query predicate positionalPatterns(PositionalPatternExpr pp, Expr parent, int n, Expr child) {
parent = pp.getParent() and
child = pp.getPattern(n)
}
query predicate caseStatements(CaseStmt case) { any() }
query predicate recursivePatternCases(RecursivePatternCase case, RecursivePatternExpr p) {
p = case.getRecursivePattern()
}
query predicate recursiveCasePatternDecl(
RecursivePatternCase case, TypeAccess ta, LocalVariableDeclExpr decl
) {
ta = case.getTypeAccess() and decl = case.getVariableDeclExpr()
}
query predicate recursivePatternDecl(RecursivePatternExpr pattern, LocalVariableDeclExpr decl) {
decl = pattern.getVariableDeclExpr()
}
query predicate recursivePatterns(RecursivePatternExpr expr) { any() }
query predicate discards(DiscardExpr discard) { any() }
query predicate isExprs(IsExpr is) { any() }
query predicate isRecursivePatternExpr(IsRecursivePatternExpr expr) { any() }
query predicate isRecursivePatternExprWithDecl(
IsRecursivePatternExpr expr, LocalVariableDeclExpr decl
) {
decl = expr.getVariableDeclExpr()
}

View File

@@ -0,0 +1,160 @@
| patterns.cs:98:10:98:20 | enter Expressions | patterns.cs:99:5:121:5 | {...} | semmle.label | successor |
| patterns.cs:99:5:121:5 | {...} | patterns.cs:100:9:103:10 | ... ...; | semmle.label | successor |
| patterns.cs:100:9:103:10 | ... ...; | patterns.cs:100:20:103:9 | ... switch { ... } | semmle.label | successor |
| patterns.cs:100:13:103:9 | String size = ... | patterns.cs:105:9:105:27 | ... ...; | semmle.label | successor |
| patterns.cs:100:20:100:20 | access to parameter x | patterns.cs:101:13:101:40 | ... => ... | semmle.label | successor |
| patterns.cs:100:20:103:9 | ... switch { ... } | patterns.cs:100:20:100:20 | access to parameter x | semmle.label | successor |
| patterns.cs:101:13:101:17 | Int32 y | patterns.cs:101:24:101:24 | access to local variable y | semmle.label | match |
| patterns.cs:101:13:101:17 | Int32 y | patterns.cs:102:13:102:24 | ... => ... | semmle.label | no-match |
| patterns.cs:101:13:101:40 | ... => ... | patterns.cs:101:13:101:17 | Int32 y | semmle.label | successor |
| patterns.cs:101:24:101:24 | access to local variable y | patterns.cs:101:28:101:29 | 10 | semmle.label | successor |
| patterns.cs:101:24:101:29 | ... > ... | patterns.cs:101:34:101:40 | "large" | semmle.label | true |
| patterns.cs:101:24:101:29 | ... > ... | patterns.cs:102:13:102:24 | ... => ... | semmle.label | false |
| patterns.cs:101:28:101:29 | 10 | patterns.cs:101:24:101:29 | ... > ... | semmle.label | successor |
| patterns.cs:101:34:101:40 | "large" | patterns.cs:100:13:103:9 | String size = ... | semmle.label | successor |
| patterns.cs:102:13:102:13 | _ | patterns.cs:102:18:102:24 | "small" | semmle.label | match |
| patterns.cs:102:13:102:24 | ... => ... | patterns.cs:102:13:102:13 | _ | semmle.label | successor |
| patterns.cs:102:18:102:24 | "small" | patterns.cs:100:13:103:9 | String size = ... | semmle.label | successor |
| patterns.cs:105:9:105:27 | ... ...; | patterns.cs:105:18:105:18 | 0 | semmle.label | successor |
| patterns.cs:105:13:105:18 | Int32 x0 = ... | patterns.cs:105:26:105:26 | 0 | semmle.label | successor |
| patterns.cs:105:18:105:18 | 0 | patterns.cs:105:13:105:18 | Int32 x0 = ... | semmle.label | successor |
| patterns.cs:105:21:105:26 | Int32 y0 = ... | patterns.cs:108:9:112:10 | ...; | semmle.label | successor |
| patterns.cs:105:26:105:26 | 0 | patterns.cs:105:21:105:26 | Int32 y0 = ... | semmle.label | successor |
| patterns.cs:108:9:108:20 | (..., ...) | patterns.cs:108:24:112:9 | ... switch { ... } | semmle.label | successor |
| patterns.cs:108:9:112:9 | ... = ... | patterns.cs:115:9:120:10 | ...; | semmle.label | successor |
| patterns.cs:108:9:112:10 | ...; | patterns.cs:108:14:108:15 | Int32 x1 | semmle.label | successor |
| patterns.cs:108:14:108:15 | Int32 x1 | patterns.cs:108:18:108:19 | Int32 y1 | semmle.label | successor |
| patterns.cs:108:18:108:19 | Int32 y1 | patterns.cs:108:9:108:20 | (..., ...) | semmle.label | successor |
| patterns.cs:108:24:108:31 | (..., ...) | patterns.cs:110:13:110:26 | ... => ... | semmle.label | successor |
| patterns.cs:108:24:112:9 | ... switch { ... } | patterns.cs:108:25:108:26 | access to local variable x0 | semmle.label | successor |
| patterns.cs:108:25:108:26 | access to local variable x0 | patterns.cs:108:29:108:30 | access to local variable y0 | semmle.label | successor |
| patterns.cs:108:29:108:30 | access to local variable y0 | patterns.cs:108:24:108:31 | (..., ...) | semmle.label | successor |
| patterns.cs:110:13:110:17 | ( ... ) | patterns.cs:110:13:110:17 | { ... } | semmle.label | successor |
| patterns.cs:110:13:110:17 | { ... } | patterns.cs:110:23:110:23 | 1 | semmle.label | match |
| patterns.cs:110:13:110:17 | { ... } | patterns.cs:111:13:111:26 | ... => ... | semmle.label | no-match |
| patterns.cs:110:13:110:26 | ... => ... | patterns.cs:110:14:110:14 | 0 | semmle.label | successor |
| patterns.cs:110:14:110:14 | 0 | patterns.cs:110:16:110:16 | 1 | semmle.label | successor |
| patterns.cs:110:16:110:16 | 1 | patterns.cs:110:13:110:17 | ( ... ) | semmle.label | successor |
| patterns.cs:110:22:110:26 | (..., ...) | patterns.cs:108:9:112:9 | ... = ... | semmle.label | successor |
| patterns.cs:110:23:110:23 | 1 | patterns.cs:110:25:110:25 | 0 | semmle.label | successor |
| patterns.cs:110:25:110:25 | 0 | patterns.cs:110:22:110:26 | (..., ...) | semmle.label | successor |
| patterns.cs:111:13:111:17 | ( ... ) | patterns.cs:111:13:111:17 | { ... } | semmle.label | successor |
| patterns.cs:111:13:111:17 | { ... } | patterns.cs:98:10:98:20 | exit Expressions | semmle.label | exception(InvalidOperationException) |
| patterns.cs:111:13:111:17 | { ... } | patterns.cs:111:23:111:23 | 0 | semmle.label | match |
| patterns.cs:111:13:111:26 | ... => ... | patterns.cs:111:14:111:14 | 1 | semmle.label | successor |
| patterns.cs:111:14:111:14 | 1 | patterns.cs:111:16:111:16 | 0 | semmle.label | successor |
| patterns.cs:111:16:111:16 | 0 | patterns.cs:111:13:111:17 | ( ... ) | semmle.label | successor |
| patterns.cs:111:22:111:26 | (..., ...) | patterns.cs:108:9:112:9 | ... = ... | semmle.label | successor |
| patterns.cs:111:23:111:23 | 0 | patterns.cs:111:25:111:25 | 1 | semmle.label | successor |
| patterns.cs:111:25:111:25 | 1 | patterns.cs:111:22:111:26 | (..., ...) | semmle.label | successor |
| patterns.cs:115:9:115:16 | (..., ...) | patterns.cs:115:20:120:9 | ... switch { ... } | semmle.label | successor |
| patterns.cs:115:9:120:9 | ... = ... | patterns.cs:98:10:98:20 | exit Expressions | semmle.label | successor |
| patterns.cs:115:9:120:10 | ...; | patterns.cs:115:9:115:16 | (..., ...) | semmle.label | successor |
| patterns.cs:115:20:115:27 | (..., ...) | patterns.cs:117:13:117:33 | ... => ... | semmle.label | successor |
| patterns.cs:115:20:120:9 | ... switch { ... } | patterns.cs:115:21:115:22 | access to local variable x0 | semmle.label | successor |
| patterns.cs:115:21:115:22 | access to local variable x0 | patterns.cs:115:25:115:26 | access to local variable y0 | semmle.label | successor |
| patterns.cs:115:25:115:26 | access to local variable y0 | patterns.cs:115:20:115:27 | (..., ...) | semmle.label | successor |
| patterns.cs:117:13:117:22 | ( ... ) | patterns.cs:117:13:117:22 | { ... } | semmle.label | successor |
| patterns.cs:117:13:117:22 | { ... } | patterns.cs:117:28:117:29 | access to local variable y2 | semmle.label | match |
| patterns.cs:117:13:117:22 | { ... } | patterns.cs:118:13:118:34 | ... => ... | semmle.label | no-match |
| patterns.cs:117:13:117:33 | ... => ... | patterns.cs:117:14:117:14 | 0 | semmle.label | successor |
| patterns.cs:117:14:117:14 | 0 | patterns.cs:117:16:117:21 | Int32 y2 | semmle.label | successor |
| patterns.cs:117:16:117:21 | Int32 y2 | patterns.cs:117:13:117:22 | ( ... ) | semmle.label | successor |
| patterns.cs:117:27:117:33 | (..., ...) | patterns.cs:115:9:120:9 | ... = ... | semmle.label | successor |
| patterns.cs:117:28:117:29 | access to local variable y2 | patterns.cs:117:32:117:32 | 0 | semmle.label | successor |
| patterns.cs:117:32:117:32 | 0 | patterns.cs:117:27:117:33 | (..., ...) | semmle.label | successor |
| patterns.cs:118:13:118:23 | ( ... ) | patterns.cs:118:13:118:23 | { ... } | semmle.label | successor |
| patterns.cs:118:13:118:23 | { ... } | patterns.cs:118:29:118:29 | 0 | semmle.label | match |
| patterns.cs:118:13:118:23 | { ... } | patterns.cs:119:13:119:38 | ... => ... | semmle.label | no-match |
| patterns.cs:118:13:118:34 | ... => ... | patterns.cs:118:14:118:19 | Int32 x2 | semmle.label | successor |
| patterns.cs:118:14:118:19 | Int32 x2 | patterns.cs:118:22:118:22 | 0 | semmle.label | successor |
| patterns.cs:118:22:118:22 | 0 | patterns.cs:118:13:118:23 | ( ... ) | semmle.label | successor |
| patterns.cs:118:28:118:34 | (..., ...) | patterns.cs:115:9:120:9 | ... = ... | semmle.label | successor |
| patterns.cs:118:29:118:29 | 0 | patterns.cs:118:32:118:33 | access to local variable x2 | semmle.label | successor |
| patterns.cs:118:32:118:33 | access to local variable x2 | patterns.cs:118:28:118:34 | (..., ...) | semmle.label | successor |
| patterns.cs:119:13:119:28 | ( ... ) | patterns.cs:119:13:119:28 | { ... } | semmle.label | successor |
| patterns.cs:119:13:119:28 | { ... } | patterns.cs:98:10:98:20 | exit Expressions | semmle.label | exception(InvalidOperationException) |
| patterns.cs:119:13:119:28 | { ... } | patterns.cs:119:34:119:34 | 0 | semmle.label | match |
| patterns.cs:119:13:119:38 | ... => ... | patterns.cs:119:14:119:19 | Int32 x2 | semmle.label | successor |
| patterns.cs:119:14:119:19 | Int32 x2 | patterns.cs:119:22:119:27 | Int32 y2 | semmle.label | successor |
| patterns.cs:119:22:119:27 | Int32 y2 | patterns.cs:119:13:119:28 | ( ... ) | semmle.label | successor |
| patterns.cs:119:33:119:38 | (..., ...) | patterns.cs:115:9:120:9 | ... = ... | semmle.label | successor |
| patterns.cs:119:34:119:34 | 0 | patterns.cs:119:37:119:37 | 0 | semmle.label | successor |
| patterns.cs:119:37:119:37 | 0 | patterns.cs:119:33:119:38 | (..., ...) | semmle.label | successor |
| patterns.cs:123:10:123:21 | enter Expressions2 | patterns.cs:124:5:147:5 | {...} | semmle.label | successor |
| patterns.cs:124:5:147:5 | {...} | patterns.cs:125:9:125:39 | ... ...; | semmle.label | successor |
| patterns.cs:125:9:125:39 | ... ...; | patterns.cs:125:17:125:38 | object creation of type MyStruct | semmle.label | successor |
| patterns.cs:125:13:125:38 | MyStruct s = ... | patterns.cs:126:9:132:10 | ... ...; | semmle.label | successor |
| patterns.cs:125:17:125:38 | object creation of type MyStruct | patterns.cs:125:36:125:36 | 0 | semmle.label | successor |
| patterns.cs:125:30:125:38 | { ..., ... } | patterns.cs:125:13:125:38 | MyStruct s = ... | semmle.label | successor |
| patterns.cs:125:32:125:36 | ... = ... | patterns.cs:125:30:125:38 | { ..., ... } | semmle.label | successor |
| patterns.cs:125:36:125:36 | 0 | patterns.cs:125:32:125:36 | ... = ... | semmle.label | successor |
| patterns.cs:126:9:132:10 | ... ...; | patterns.cs:126:17:132:9 | ... switch { ... } | semmle.label | successor |
| patterns.cs:126:13:132:9 | Int32 r = ... | patterns.cs:134:9:146:9 | try {...} ... | semmle.label | successor |
| patterns.cs:126:17:126:17 | access to local variable s | patterns.cs:128:13:128:49 | ... => ... | semmle.label | successor |
| patterns.cs:126:17:132:9 | ... switch { ... } | patterns.cs:126:17:126:17 | access to local variable s | semmle.label | successor |
| patterns.cs:128:13:128:33 | { ... } | patterns.cs:128:40:128:40 | access to local variable x | semmle.label | match |
| patterns.cs:128:13:128:33 | { ... } | patterns.cs:129:13:129:38 | ... => ... | semmle.label | no-match |
| patterns.cs:128:13:128:49 | ... => ... | patterns.cs:128:27:128:31 | Int32 x | semmle.label | successor |
| patterns.cs:128:22:128:33 | { ... } | patterns.cs:128:13:128:33 | { ... } | semmle.label | successor |
| patterns.cs:128:27:128:31 | Int32 x | patterns.cs:128:22:128:33 | { ... } | semmle.label | successor |
| patterns.cs:128:40:128:40 | access to local variable x | patterns.cs:128:44:128:44 | 2 | semmle.label | successor |
| patterns.cs:128:40:128:44 | ... > ... | patterns.cs:128:49:128:49 | 0 | semmle.label | true |
| patterns.cs:128:40:128:44 | ... > ... | patterns.cs:129:13:129:38 | ... => ... | semmle.label | false |
| patterns.cs:128:44:128:44 | 2 | patterns.cs:128:40:128:44 | ... > ... | semmle.label | successor |
| patterns.cs:128:49:128:49 | 0 | patterns.cs:126:13:132:9 | Int32 r = ... | semmle.label | successor |
| patterns.cs:129:13:129:33 | MyStruct ms | patterns.cs:129:27:129:28 | 10 | semmle.label | successor |
| patterns.cs:129:13:129:33 | { ... } | patterns.cs:129:38:129:38 | 1 | semmle.label | match |
| patterns.cs:129:13:129:33 | { ... } | patterns.cs:130:13:130:23 | ... => ... | semmle.label | no-match |
| patterns.cs:129:13:129:38 | ... => ... | patterns.cs:129:13:129:33 | MyStruct ms | semmle.label | successor |
| patterns.cs:129:22:129:30 | { ... } | patterns.cs:129:13:129:33 | { ... } | semmle.label | successor |
| patterns.cs:129:27:129:28 | 10 | patterns.cs:129:22:129:30 | { ... } | semmle.label | successor |
| patterns.cs:129:38:129:38 | 1 | patterns.cs:126:13:132:9 | Int32 r = ... | semmle.label | successor |
| patterns.cs:130:13:130:18 | ( ... ) | patterns.cs:130:13:130:18 | { ... } | semmle.label | successor |
| patterns.cs:130:13:130:18 | { ... } | patterns.cs:130:23:130:23 | 2 | semmle.label | match |
| patterns.cs:130:13:130:18 | { ... } | patterns.cs:131:13:131:27 | ... => ... | semmle.label | no-match |
| patterns.cs:130:13:130:23 | ... => ... | patterns.cs:130:14:130:14 | 1 | semmle.label | successor |
| patterns.cs:130:14:130:14 | 1 | patterns.cs:130:17:130:17 | 2 | semmle.label | successor |
| patterns.cs:130:17:130:17 | 2 | patterns.cs:130:13:130:18 | ( ... ) | semmle.label | successor |
| patterns.cs:130:23:130:23 | 2 | patterns.cs:126:13:132:9 | Int32 r = ... | semmle.label | successor |
| patterns.cs:131:13:131:22 | (..., ...) | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | exception(InvalidOperationException) |
| patterns.cs:131:13:131:22 | (..., ...) | patterns.cs:131:27:131:27 | 3 | semmle.label | match |
| patterns.cs:131:13:131:27 | ... => ... | patterns.cs:131:18:131:18 | Int32 x | semmle.label | successor |
| patterns.cs:131:18:131:18 | Int32 x | patterns.cs:131:21:131:21 | _ | semmle.label | successor |
| patterns.cs:131:21:131:21 | _ | patterns.cs:131:13:131:22 | (..., ...) | semmle.label | successor |
| patterns.cs:131:27:131:27 | 3 | patterns.cs:126:13:132:9 | Int32 r = ... | semmle.label | successor |
| patterns.cs:134:9:146:9 | try {...} ... | patterns.cs:135:9:142:9 | {...} | semmle.label | successor |
| patterns.cs:135:9:142:9 | {...} | patterns.cs:136:13:141:14 | ...; | semmle.label | successor |
| patterns.cs:136:13:141:13 | ... = ... | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | successor |
| patterns.cs:136:13:141:14 | ...; | patterns.cs:136:17:141:13 | ... switch { ... } | semmle.label | successor |
| patterns.cs:136:17:136:17 | 0 | patterns.cs:138:17:138:50 | ... => ... | semmle.label | successor |
| patterns.cs:136:17:141:13 | ... switch { ... } | patterns.cs:136:17:136:17 | 0 | semmle.label | successor |
| patterns.cs:138:17:138:17 | 1 | patterns.cs:138:28:138:50 | object creation of type ArgumentException | semmle.label | match |
| patterns.cs:138:17:138:17 | 1 | patterns.cs:139:17:139:22 | ... => ... | semmle.label | no-match |
| patterns.cs:138:17:138:50 | ... => ... | patterns.cs:138:17:138:17 | 1 | semmle.label | successor |
| patterns.cs:138:22:138:50 | throw ... | patterns.cs:143:9:146:9 | [exception: ArgumentException] catch (...) {...} | semmle.label | exception(ArgumentException) |
| patterns.cs:138:28:138:50 | object creation of type ArgumentException | patterns.cs:138:22:138:50 | throw ... | semmle.label | successor |
| patterns.cs:138:28:138:50 | object creation of type ArgumentException | patterns.cs:143:9:146:9 | [exception: Exception] catch (...) {...} | semmle.label | exception(Exception) |
| patterns.cs:139:17:139:17 | 2 | patterns.cs:139:22:139:22 | 3 | semmle.label | match |
| patterns.cs:139:17:139:17 | 2 | patterns.cs:140:17:140:42 | ... => ... | semmle.label | no-match |
| patterns.cs:139:17:139:22 | ... => ... | patterns.cs:139:17:139:17 | 2 | semmle.label | successor |
| patterns.cs:139:22:139:22 | 3 | patterns.cs:136:13:141:13 | ... = ... | semmle.label | successor |
| patterns.cs:140:17:140:24 | Object y | patterns.cs:140:31:140:31 | access to local variable y | semmle.label | match |
| patterns.cs:140:17:140:24 | Object y | patterns.cs:143:9:146:9 | [exception: InvalidOperationException] catch (...) {...} | semmle.label | exception(InvalidOperationException) |
| patterns.cs:140:17:140:42 | ... => ... | patterns.cs:140:17:140:24 | Object y | semmle.label | successor |
| patterns.cs:140:31:140:31 | access to local variable y | patterns.cs:140:36:140:37 | { ... } | semmle.label | successor |
| patterns.cs:140:31:140:37 | ... is { ... } | patterns.cs:140:42:140:42 | 4 | semmle.label | true |
| patterns.cs:140:31:140:37 | ... is { ... } | patterns.cs:143:9:146:9 | [exception: InvalidOperationException] catch (...) {...} | semmle.label | exception(InvalidOperationException) |
| patterns.cs:140:36:140:37 | { ... } | patterns.cs:140:31:140:37 | ... is { ... } | semmle.label | successor |
| patterns.cs:140:36:140:37 | { ... } | patterns.cs:140:36:140:37 | { ... } | semmle.label | successor |
| patterns.cs:140:42:140:42 | 4 | patterns.cs:136:13:141:13 | ... = ... | semmle.label | successor |
| patterns.cs:143:9:146:9 | [exception: ArgumentException] catch (...) {...} | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | exception(ArgumentException) |
| patterns.cs:143:9:146:9 | [exception: Exception] catch (...) {...} | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | exception(Exception) |
| patterns.cs:143:9:146:9 | [exception: Exception] catch (...) {...} | patterns.cs:143:41:143:42 | [exception: Exception] InvalidOperationException ex | semmle.label | match |
| patterns.cs:143:9:146:9 | [exception: InvalidOperationException] catch (...) {...} | patterns.cs:143:41:143:42 | [exception: InvalidOperationException] InvalidOperationException ex | semmle.label | match |
| patterns.cs:143:41:143:42 | [exception: Exception] InvalidOperationException ex | patterns.cs:144:9:146:9 | {...} | semmle.label | successor |
| patterns.cs:143:41:143:42 | [exception: InvalidOperationException] InvalidOperationException ex | patterns.cs:144:9:146:9 | {...} | semmle.label | successor |
| patterns.cs:144:9:146:9 | {...} | patterns.cs:145:13:145:51 | ...; | semmle.label | successor |
| patterns.cs:145:13:145:50 | call to method WriteLine | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | successor |
| patterns.cs:145:13:145:51 | ...; | patterns.cs:145:31:145:49 | "Invalid operation" | semmle.label | successor |
| patterns.cs:145:31:145:49 | "Invalid operation" | patterns.cs:145:13:145:50 | call to method WriteLine | semmle.label | successor |

View File

@@ -0,0 +1,10 @@
import csharp
query predicate edges(ControlFlow::Node a, ControlFlow::Node b, string label, string value) {
exists(ControlFlow::SuccessorType t |
a.getEnclosingCallable().getName().matches("Expressions%") and
b = a.getASuccessorByType(t) and
label = "semmle.label" and
value = t.toString()
)
}

View File

@@ -0,0 +1,176 @@
| patterns.cs:32:10:32:25 | enter SwitchStatements | patterns.cs:33:5:96:5 | {...} | semmle.label | successor |
| patterns.cs:33:5:96:5 | {...} | patterns.cs:34:9:34:39 | ... ...; | semmle.label | successor |
| patterns.cs:34:9:34:39 | ... ...; | patterns.cs:34:17:34:38 | object creation of type MyStruct | semmle.label | successor |
| patterns.cs:34:13:34:38 | MyStruct s = ... | patterns.cs:36:9:44:9 | switch (...) {...} | semmle.label | successor |
| patterns.cs:34:17:34:38 | object creation of type MyStruct | patterns.cs:34:36:34:36 | 0 | semmle.label | successor |
| patterns.cs:34:30:34:38 | { ..., ... } | patterns.cs:34:13:34:38 | MyStruct s = ... | semmle.label | successor |
| patterns.cs:34:32:34:36 | ... = ... | patterns.cs:34:30:34:38 | { ..., ... } | semmle.label | successor |
| patterns.cs:34:36:34:36 | 0 | patterns.cs:34:32:34:36 | ... = ... | semmle.label | successor |
| patterns.cs:36:9:44:9 | switch (...) {...} | patterns.cs:36:17:36:17 | access to local variable s | semmle.label | successor |
| patterns.cs:36:17:36:17 | access to local variable s | patterns.cs:38:13:38:47 | case MyStruct ms1: | semmle.label | successor |
| patterns.cs:38:13:38:47 | case MyStruct ms1: | patterns.cs:38:18:38:25 | access to type MyStruct | semmle.label | successor |
| patterns.cs:38:18:38:25 | access to type MyStruct | patterns.cs:38:18:38:29 | MyStruct ms1 | semmle.label | match |
| patterns.cs:38:18:38:25 | access to type MyStruct | patterns.cs:41:13:41:46 | case MyStruct ms2: | semmle.label | no-match |
| patterns.cs:38:18:38:29 | MyStruct ms1 | patterns.cs:38:36:38:38 | access to local variable ms1 | semmle.label | successor |
| patterns.cs:38:36:38:38 | access to local variable ms1 | patterns.cs:38:36:38:40 | access to field X | semmle.label | successor |
| patterns.cs:38:36:38:40 | access to field X | patterns.cs:38:45:38:46 | 10 | semmle.label | successor |
| patterns.cs:38:36:38:46 | ... == ... | patterns.cs:39:17:39:56 | ...; | semmle.label | true |
| patterns.cs:38:36:38:46 | ... == ... | patterns.cs:41:13:41:46 | case MyStruct ms2: | semmle.label | false |
| patterns.cs:38:45:38:46 | 10 | patterns.cs:38:36:38:46 | ... == ... | semmle.label | successor |
| patterns.cs:39:17:39:55 | call to method WriteLine | patterns.cs:40:17:40:22 | break; | semmle.label | successor |
| patterns.cs:39:17:39:56 | ...; | patterns.cs:39:35:39:54 | "Hit the breakpoint" | semmle.label | successor |
| patterns.cs:39:35:39:54 | "Hit the breakpoint" | patterns.cs:39:17:39:55 | call to method WriteLine | semmle.label | successor |
| patterns.cs:40:17:40:22 | break; | patterns.cs:46:9:63:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:41:13:41:46 | case MyStruct ms2: | patterns.cs:41:18:41:25 | access to type MyStruct | semmle.label | successor |
| patterns.cs:41:18:41:25 | access to type MyStruct | patterns.cs:41:18:41:29 | MyStruct ms2 | semmle.label | match |
| patterns.cs:41:18:41:25 | access to type MyStruct | patterns.cs:46:9:63:9 | switch (...) {...} | semmle.label | no-match |
| patterns.cs:41:18:41:29 | MyStruct ms2 | patterns.cs:41:36:41:38 | access to local variable ms2 | semmle.label | successor |
| patterns.cs:41:36:41:38 | access to local variable ms2 | patterns.cs:41:36:41:40 | access to field X | semmle.label | successor |
| patterns.cs:41:36:41:40 | access to field X | patterns.cs:41:44:41:45 | 10 | semmle.label | successor |
| patterns.cs:41:36:41:45 | ... < ... | patterns.cs:42:17:42:59 | ...; | semmle.label | true |
| patterns.cs:41:36:41:45 | ... < ... | patterns.cs:46:9:63:9 | switch (...) {...} | semmle.label | false |
| patterns.cs:41:44:41:45 | 10 | patterns.cs:41:36:41:45 | ... < ... | semmle.label | successor |
| patterns.cs:42:17:42:58 | call to method WriteLine | patterns.cs:43:17:43:22 | break; | semmle.label | successor |
| patterns.cs:42:17:42:59 | ...; | patterns.cs:42:35:42:57 | "Missed the breakpoint" | semmle.label | successor |
| patterns.cs:42:35:42:57 | "Missed the breakpoint" | patterns.cs:42:17:42:58 | call to method WriteLine | semmle.label | successor |
| patterns.cs:43:17:43:22 | break; | patterns.cs:46:9:63:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:46:9:63:9 | switch (...) {...} | patterns.cs:46:17:46:17 | access to local variable s | semmle.label | successor |
| patterns.cs:46:17:46:17 | access to local variable s | patterns.cs:48:13:48:50 | case { ... }: | semmle.label | successor |
| patterns.cs:48:13:48:50 | case { ... }: | patterns.cs:48:18:48:25 | access to type MyStruct | semmle.label | successor |
| patterns.cs:48:18:48:25 | access to type MyStruct | patterns.cs:48:32:48:36 | Int32 x | semmle.label | match |
| patterns.cs:48:18:48:25 | access to type MyStruct | patterns.cs:51:13:51:39 | case { ... }: | semmle.label | no-match |
| patterns.cs:48:18:48:38 | { ... } | patterns.cs:48:45:48:45 | access to local variable x | semmle.label | match |
| patterns.cs:48:18:48:38 | { ... } | patterns.cs:51:13:51:39 | case { ... }: | semmle.label | no-match |
| patterns.cs:48:27:48:38 | { ... } | patterns.cs:48:18:48:38 | { ... } | semmle.label | successor |
| patterns.cs:48:32:48:36 | Int32 x | patterns.cs:48:27:48:38 | { ... } | semmle.label | successor |
| patterns.cs:48:45:48:45 | access to local variable x | patterns.cs:48:49:48:49 | 2 | semmle.label | successor |
| patterns.cs:48:45:48:49 | ... > ... | patterns.cs:49:17:49:37 | ...; | semmle.label | true |
| patterns.cs:48:45:48:49 | ... > ... | patterns.cs:51:13:51:39 | case { ... }: | semmle.label | false |
| patterns.cs:48:49:48:49 | 2 | patterns.cs:48:45:48:49 | ... > ... | semmle.label | successor |
| patterns.cs:49:17:49:36 | call to method WriteLine | patterns.cs:50:17:50:22 | break; | semmle.label | successor |
| patterns.cs:49:17:49:37 | ...; | patterns.cs:49:35:49:35 | access to local variable x | semmle.label | successor |
| patterns.cs:49:35:49:35 | access to local variable x | patterns.cs:49:17:49:36 | call to method WriteLine | semmle.label | successor |
| patterns.cs:50:17:50:22 | break; | patterns.cs:65:9:73:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:51:13:51:39 | case { ... }: | patterns.cs:51:18:51:25 | access to type MyStruct | semmle.label | successor |
| patterns.cs:51:18:51:25 | access to type MyStruct | patterns.cs:51:32:51:33 | 10 | semmle.label | match |
| patterns.cs:51:18:51:25 | access to type MyStruct | patterns.cs:54:13:54:43 | case { ... }: | semmle.label | no-match |
| patterns.cs:51:18:51:38 | MyStruct ms | patterns.cs:52:17:52:56 | ...; | semmle.label | successor |
| patterns.cs:51:18:51:38 | { ... } | patterns.cs:51:18:51:38 | MyStruct ms | semmle.label | match |
| patterns.cs:51:18:51:38 | { ... } | patterns.cs:54:13:54:43 | case { ... }: | semmle.label | no-match |
| patterns.cs:51:27:51:35 | { ... } | patterns.cs:51:18:51:38 | { ... } | semmle.label | successor |
| patterns.cs:51:32:51:33 | 10 | patterns.cs:51:27:51:35 | { ... } | semmle.label | successor |
| patterns.cs:52:17:52:55 | call to method WriteLine | patterns.cs:53:17:53:22 | break; | semmle.label | successor |
| patterns.cs:52:17:52:56 | ...; | patterns.cs:52:35:52:54 | "Hit the breakpoint" | semmle.label | successor |
| patterns.cs:52:35:52:54 | "Hit the breakpoint" | patterns.cs:52:17:52:55 | call to method WriteLine | semmle.label | successor |
| patterns.cs:53:17:53:22 | break; | patterns.cs:65:9:73:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:54:13:54:43 | case { ... }: | patterns.cs:54:23:54:28 | Int32 x2 | semmle.label | successor |
| patterns.cs:54:18:54:30 | { ... } | patterns.cs:54:18:54:30 | { ... } | semmle.label | successor |
| patterns.cs:54:18:54:30 | { ... } | patterns.cs:54:37:54:38 | access to local variable x2 | semmle.label | match |
| patterns.cs:54:18:54:30 | { ... } | patterns.cs:57:13:57:24 | case { ... }: | semmle.label | no-match |
| patterns.cs:54:23:54:28 | Int32 x2 | patterns.cs:54:18:54:30 | { ... } | semmle.label | successor |
| patterns.cs:54:37:54:38 | access to local variable x2 | patterns.cs:54:42:54:42 | 2 | semmle.label | successor |
| patterns.cs:54:37:54:42 | ... > ... | patterns.cs:55:17:55:38 | ...; | semmle.label | true |
| patterns.cs:54:37:54:42 | ... > ... | patterns.cs:57:13:57:24 | case { ... }: | semmle.label | false |
| patterns.cs:54:42:54:42 | 2 | patterns.cs:54:37:54:42 | ... > ... | semmle.label | successor |
| patterns.cs:55:17:55:37 | call to method WriteLine | patterns.cs:56:17:56:22 | break; | semmle.label | successor |
| patterns.cs:55:17:55:38 | ...; | patterns.cs:55:35:55:36 | access to local variable x2 | semmle.label | successor |
| patterns.cs:55:35:55:36 | access to local variable x2 | patterns.cs:55:17:55:37 | call to method WriteLine | semmle.label | successor |
| patterns.cs:56:17:56:22 | break; | patterns.cs:65:9:73:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:57:13:57:24 | case { ... }: | patterns.cs:57:19:57:19 | 1 | semmle.label | successor |
| patterns.cs:57:18:57:23 | ( ... ) | patterns.cs:57:18:57:23 | { ... } | semmle.label | successor |
| patterns.cs:57:18:57:23 | { ... } | patterns.cs:58:17:58:22 | break; | semmle.label | match |
| patterns.cs:57:18:57:23 | { ... } | patterns.cs:59:13:59:28 | case ...: | semmle.label | no-match |
| patterns.cs:57:19:57:19 | 1 | patterns.cs:57:22:57:22 | 2 | semmle.label | successor |
| patterns.cs:57:22:57:22 | 2 | patterns.cs:57:18:57:23 | ( ... ) | semmle.label | successor |
| patterns.cs:58:17:58:22 | break; | patterns.cs:65:9:73:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:59:13:59:28 | case ...: | patterns.cs:59:23:59:23 | Int32 x | semmle.label | successor |
| patterns.cs:59:18:59:27 | (..., ...) | patterns.cs:60:17:60:22 | break; | semmle.label | match |
| patterns.cs:59:18:59:27 | (..., ...) | patterns.cs:61:13:61:20 | default: | semmle.label | no-match |
| patterns.cs:59:23:59:23 | Int32 x | patterns.cs:59:26:59:26 | Int32 y | semmle.label | successor |
| patterns.cs:59:26:59:26 | Int32 y | patterns.cs:59:18:59:27 | (..., ...) | semmle.label | successor |
| patterns.cs:60:17:60:22 | break; | patterns.cs:65:9:73:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:61:13:61:20 | default: | patterns.cs:62:17:62:22 | break; | semmle.label | successor |
| patterns.cs:62:17:62:22 | break; | patterns.cs:65:9:73:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:65:9:73:9 | switch (...) {...} | patterns.cs:65:17:65:17 | access to local variable s | semmle.label | successor |
| patterns.cs:65:17:65:17 | access to local variable s | patterns.cs:67:13:67:50 | case { ... }: | semmle.label | successor |
| patterns.cs:67:13:67:50 | case { ... }: | patterns.cs:67:18:67:25 | access to type MyStruct | semmle.label | successor |
| patterns.cs:67:18:67:25 | access to type MyStruct | patterns.cs:67:32:67:36 | Int32 x | semmle.label | match |
| patterns.cs:67:18:67:25 | access to type MyStruct | patterns.cs:70:13:70:51 | case { ... }: | semmle.label | no-match |
| patterns.cs:67:18:67:38 | { ... } | patterns.cs:67:45:67:45 | access to local variable x | semmle.label | match |
| patterns.cs:67:18:67:38 | { ... } | patterns.cs:70:13:70:51 | case { ... }: | semmle.label | no-match |
| patterns.cs:67:27:67:38 | { ... } | patterns.cs:67:18:67:38 | { ... } | semmle.label | successor |
| patterns.cs:67:32:67:36 | Int32 x | patterns.cs:67:27:67:38 | { ... } | semmle.label | successor |
| patterns.cs:67:45:67:45 | access to local variable x | patterns.cs:67:49:67:49 | 2 | semmle.label | successor |
| patterns.cs:67:45:67:49 | ... > ... | patterns.cs:68:17:68:37 | ...; | semmle.label | true |
| patterns.cs:67:45:67:49 | ... > ... | patterns.cs:70:13:70:51 | case { ... }: | semmle.label | false |
| patterns.cs:67:49:67:49 | 2 | patterns.cs:67:45:67:49 | ... > ... | semmle.label | successor |
| patterns.cs:68:17:68:36 | call to method WriteLine | patterns.cs:69:17:69:22 | break; | semmle.label | successor |
| patterns.cs:68:17:68:37 | ...; | patterns.cs:68:35:68:35 | access to local variable x | semmle.label | successor |
| patterns.cs:68:35:68:35 | access to local variable x | patterns.cs:68:17:68:36 | call to method WriteLine | semmle.label | successor |
| patterns.cs:69:17:69:22 | break; | patterns.cs:76:9:84:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:70:13:70:51 | case { ... }: | patterns.cs:70:18:70:25 | access to type MyStruct | semmle.label | successor |
| patterns.cs:70:18:70:25 | access to type MyStruct | patterns.cs:70:32:70:33 | 10 | semmle.label | match |
| patterns.cs:70:18:70:25 | access to type MyStruct | patterns.cs:76:9:84:9 | switch (...) {...} | semmle.label | no-match |
| patterns.cs:70:18:70:38 | MyStruct ms | patterns.cs:70:45:70:45 | access to local variable s | semmle.label | successor |
| patterns.cs:70:18:70:38 | { ... } | patterns.cs:70:18:70:38 | MyStruct ms | semmle.label | match |
| patterns.cs:70:27:70:35 | { ... } | patterns.cs:70:18:70:38 | { ... } | semmle.label | successor |
| patterns.cs:70:32:70:33 | 10 | patterns.cs:70:27:70:35 | { ... } | semmle.label | successor |
| patterns.cs:70:45:70:45 | access to local variable s | patterns.cs:70:45:70:47 | access to field X | semmle.label | successor |
| patterns.cs:70:45:70:47 | access to field X | patterns.cs:70:50:70:50 | 0 | semmle.label | successor |
| patterns.cs:70:45:70:50 | ... == ... | patterns.cs:71:17:71:56 | ...; | semmle.label | true |
| patterns.cs:70:45:70:50 | ... == ... | patterns.cs:76:9:84:9 | switch (...) {...} | semmle.label | false |
| patterns.cs:70:50:70:50 | 0 | patterns.cs:70:45:70:50 | ... == ... | semmle.label | successor |
| patterns.cs:71:17:71:55 | call to method WriteLine | patterns.cs:72:17:72:22 | break; | semmle.label | successor |
| patterns.cs:71:17:71:56 | ...; | patterns.cs:71:35:71:54 | "Hit the breakpoint" | semmle.label | successor |
| patterns.cs:71:35:71:54 | "Hit the breakpoint" | patterns.cs:71:17:71:55 | call to method WriteLine | semmle.label | successor |
| patterns.cs:72:17:72:22 | break; | patterns.cs:76:9:84:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:76:9:84:9 | switch (...) {...} | patterns.cs:76:17:76:28 | object creation of type Object | semmle.label | successor |
| patterns.cs:76:17:76:28 | object creation of type Object | patterns.cs:78:13:78:43 | case { ... }: | semmle.label | successor |
| patterns.cs:78:13:78:43 | case { ... }: | patterns.cs:78:19:78:23 | Int32 x | semmle.label | successor |
| patterns.cs:78:18:78:33 | ( ... ) | patterns.cs:78:18:78:33 | { ... } | semmle.label | successor |
| patterns.cs:78:18:78:33 | { ... } | patterns.cs:78:40:78:40 | access to local variable x | semmle.label | match |
| patterns.cs:78:18:78:33 | { ... } | patterns.cs:80:13:80:20 | case { ... }: | semmle.label | no-match |
| patterns.cs:78:19:78:23 | Int32 x | patterns.cs:78:26:78:32 | Single y | semmle.label | successor |
| patterns.cs:78:26:78:32 | Single y | patterns.cs:78:18:78:33 | ( ... ) | semmle.label | successor |
| patterns.cs:78:40:78:40 | (...) ... | patterns.cs:78:42:78:42 | access to local variable y | semmle.label | successor |
| patterns.cs:78:40:78:40 | access to local variable x | patterns.cs:78:40:78:40 | (...) ... | semmle.label | successor |
| patterns.cs:78:40:78:42 | ... < ... | patterns.cs:79:17:79:22 | break; | semmle.label | true |
| patterns.cs:78:40:78:42 | ... < ... | patterns.cs:80:13:80:20 | case { ... }: | semmle.label | false |
| patterns.cs:78:42:78:42 | access to local variable y | patterns.cs:78:40:78:42 | ... < ... | semmle.label | successor |
| patterns.cs:79:17:79:22 | break; | patterns.cs:86:9:89:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:80:13:80:20 | case { ... }: | patterns.cs:80:18:80:19 | ( ... ) | semmle.label | successor |
| patterns.cs:80:18:80:19 | ( ... ) | patterns.cs:80:18:80:19 | { ... } | semmle.label | successor |
| patterns.cs:80:18:80:19 | { ... } | patterns.cs:81:17:81:22 | break; | semmle.label | match |
| patterns.cs:80:18:80:19 | { ... } | patterns.cs:82:13:82:20 | case { ... }: | semmle.label | no-match |
| patterns.cs:81:17:81:22 | break; | patterns.cs:86:9:89:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:82:13:82:20 | case { ... }: | patterns.cs:82:18:82:19 | { ... } | semmle.label | successor |
| patterns.cs:82:18:82:19 | { ... } | patterns.cs:82:18:82:19 | { ... } | semmle.label | successor |
| patterns.cs:82:18:82:19 | { ... } | patterns.cs:83:17:83:22 | break; | semmle.label | match |
| patterns.cs:83:17:83:22 | break; | patterns.cs:86:9:89:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:86:9:89:9 | switch (...) {...} | patterns.cs:86:16:86:16 | 1 | semmle.label | successor |
| patterns.cs:86:15:86:19 | (..., ...) | patterns.cs:88:13:88:24 | case { ... }: | semmle.label | successor |
| patterns.cs:86:16:86:16 | 1 | patterns.cs:86:18:86:18 | 2 | semmle.label | successor |
| patterns.cs:86:18:86:18 | 2 | patterns.cs:86:15:86:19 | (..., ...) | semmle.label | successor |
| patterns.cs:88:13:88:24 | case { ... }: | patterns.cs:88:19:88:19 | 1 | semmle.label | successor |
| patterns.cs:88:18:88:23 | ( ... ) | patterns.cs:88:18:88:23 | { ... } | semmle.label | successor |
| patterns.cs:88:18:88:23 | { ... } | patterns.cs:88:26:88:31 | break; | semmle.label | match |
| patterns.cs:88:19:88:19 | 1 | patterns.cs:88:22:88:22 | 2 | semmle.label | successor |
| patterns.cs:88:22:88:22 | 2 | patterns.cs:88:18:88:23 | ( ... ) | semmle.label | successor |
| patterns.cs:88:26:88:31 | break; | patterns.cs:91:9:95:9 | switch (...) {...} | semmle.label | break |
| patterns.cs:91:9:95:9 | switch (...) {...} | patterns.cs:91:17:91:17 | 1 | semmle.label | successor |
| patterns.cs:91:16:91:20 | (..., ...) | patterns.cs:93:13:93:28 | case { ... }: | semmle.label | successor |
| patterns.cs:91:17:91:17 | 1 | patterns.cs:91:19:91:19 | 2 | semmle.label | successor |
| patterns.cs:91:19:91:19 | 2 | patterns.cs:91:16:91:20 | (..., ...) | semmle.label | successor |
| patterns.cs:93:13:93:28 | case { ... }: | patterns.cs:93:19:93:19 | 1 | semmle.label | successor |
| patterns.cs:93:18:93:27 | ( ... ) | patterns.cs:93:18:93:27 | { ... } | semmle.label | successor |
| patterns.cs:93:18:93:27 | { ... } | patterns.cs:93:30:93:35 | break; | semmle.label | match |
| patterns.cs:93:18:93:27 | { ... } | patterns.cs:94:13:94:24 | case { ... }: | semmle.label | no-match |
| patterns.cs:93:19:93:19 | 1 | patterns.cs:93:22:93:26 | Int32 x | semmle.label | successor |
| patterns.cs:93:22:93:26 | Int32 x | patterns.cs:93:18:93:27 | ( ... ) | semmle.label | successor |
| patterns.cs:93:30:93:35 | break; | patterns.cs:32:10:32:25 | exit SwitchStatements | semmle.label | break |
| patterns.cs:94:13:94:24 | case { ... }: | patterns.cs:94:19:94:19 | 2 | semmle.label | successor |
| patterns.cs:94:18:94:23 | ( ... ) | patterns.cs:94:18:94:23 | { ... } | semmle.label | successor |
| patterns.cs:94:18:94:23 | { ... } | patterns.cs:94:26:94:31 | break; | semmle.label | match |
| patterns.cs:94:19:94:19 | 2 | patterns.cs:94:22:94:22 | _ | semmle.label | successor |
| patterns.cs:94:22:94:22 | _ | patterns.cs:94:18:94:23 | ( ... ) | semmle.label | successor |
| patterns.cs:94:26:94:31 | break; | patterns.cs:32:10:32:25 | exit SwitchStatements | semmle.label | break |

View File

@@ -0,0 +1,10 @@
import csharp
query predicate edges(ControlFlow::Node a, ControlFlow::Node b, string label, string value) {
exists(ControlFlow::SuccessorType t |
a.getEnclosingCallable().hasName("SwitchStatements") and
b = a.getASuccessorByType(t) and
label = "semmle.label" and
value = t.toString()
)
}