diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs index 647f3efd8b1a..eb895d774bbd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs @@ -18,13 +18,20 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE case DeclarationPatternSyntax declPattern: // Creates a single local variable declaration. { - if (declPattern.Designation is VariableDesignationSyntax designation && cx.Model(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol) + if (declPattern.Designation is VariableDesignationSyntax designation) { - var type = Type.Create(cx, symbol.Type); - - return VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, parent, child); + if (cx.Model(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol) + { + var type = Type.Create(cx, symbol.Type); + return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, parent, child); + } + if (designation is DiscardDesignationSyntax) + { + return Expressions.TypeAccess.Create(cx, declPattern.Type, parent, child); + } + throw new InternalError(designation, "Designation pattern not handled"); } - throw new InternalError(syntax, "Is pattern not handled"); + throw new InternalError(declPattern, "Declaration pattern not handled"); } case RecursivePatternSyntax recPattern: @@ -40,7 +47,7 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE { var type = Type.Create(cx, symbol.Type); - return VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(varDesignation.GetLocation()), false, parent, child); + return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), cx.Create(varDesignation.GetLocation()), false, parent, child); } else { @@ -54,7 +61,7 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE return new Discard(cx, dp, parent, child); default: - throw new InternalError(syntax, "Is pattern not handled"); + throw new InternalError(syntax, "Pattern not handled"); } } } @@ -108,7 +115,7 @@ public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionPa { var type = Type.Create(cx, symbol.Type); - VariableDeclaration.Create(cx, symbol, type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, this, 0); + VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, this, 0); } if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc) @@ -131,19 +138,14 @@ private IsPattern(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.IS)) private void PopulatePattern(PatternSyntax pattern, TypeSyntax optionalType, SyntaxToken varKeyword, VariableDesignationSyntax designation) { - bool isVar = optionalType is null; - if (!isVar) - Expressions.TypeAccess.Create(cx, optionalType, this, 1); - + var isVar = optionalType is null; if (!(designation is null) && 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)); - - VariableDeclaration.Create(cx, symbol, type, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 2); + VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 1); } + else if (!isVar) + Expressions.TypeAccess.Create(cx, optionalType, this, 1); } protected override void Populate() @@ -152,7 +154,7 @@ protected override void Populate() switch (Syntax.Pattern) { case ConstantPatternSyntax constantPattern: - Create(cx, constantPattern.Expression, this, 3); + Create(cx, constantPattern.Expression, this, 1); return; case VarPatternSyntax varPattern: PopulatePattern(varPattern, null, varPattern.VarKeyword, varPattern.Designation); @@ -161,7 +163,7 @@ protected override void Populate() PopulatePattern(declPattern, declPattern.Type, default(SyntaxToken), declPattern.Designation); return; case RecursivePatternSyntax recPattern: - new RecursivePattern(cx, recPattern, this, 3); + new RecursivePattern(cx, recPattern, this, 1); return; default: throw new InternalError(Syntax, "Is pattern not handled"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs index d8eec9b3a013..95b592bbf2a9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs @@ -66,12 +66,13 @@ protected Expression DeclareRangeVariable(Context cx, IExpressionParentEntity pa Extraction.Entities.Location nameLoc; Type declType; + TypeSyntax declTypeSyntax = null; if (getElement) { var from = node as FromClauseSyntax; - declType = from != null && from.Type != null - ? Type.Create(cx, cx.GetType(from.Type)) - : type.ElementType; + (declType, declTypeSyntax) = from != null && from.Type != null + ? (Type.Create(cx, cx.GetType(from.Type)), from.Type) + : (type.ElementType, null); } else declType = type; @@ -79,6 +80,7 @@ protected Expression DeclareRangeVariable(Context cx, IExpressionParentEntity pa var decl = VariableDeclaration.Create(cx, variableSymbol, declType, + declTypeSyntax, cx.Create(node.GetLocation()), nameLoc = cx.Create(name.GetLocation()), true, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs index a39bc78c8538..0d83f0db7729 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs @@ -18,7 +18,7 @@ protected override void Populate() { SwitchedExpr = Expression.Create(cx, Syntax.GoverningExpression, this, -1); int child = 0; - foreach(var arm in Syntax.Arms) + foreach (var arm in Syntax.Arms) { new SwitchCase(cx, arm, this, child++); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs index 3a8949f8fd77..0ed01e12bd9a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs @@ -11,10 +11,15 @@ class VariableDeclaration : Expression { VariableDeclaration(IExpressionInfo info) : base(info) { } - public static VariableDeclaration Create(Context cx, ISymbol symbol, Type type, Extraction.Entities.Location exprLocation, Extraction.Entities.Location declLocation, bool isVar, IExpressionParentEntity parent, int child) + public static VariableDeclaration Create(Context cx, ISymbol symbol, Type type, TypeSyntax optionalSyntax, Extraction.Entities.Location exprLocation, Extraction.Entities.Location declLocation, bool isVar, IExpressionParentEntity parent, int child) { var ret = new VariableDeclaration(new ExpressionInfo(cx, type, exprLocation, ExprKind.LOCAL_VAR_DECL, parent, child, false, null)); - cx.Try(null, null, () => LocalVariable.Create(cx, symbol, ret, isVar, declLocation)); + cx.Try(null, null, () => + { + LocalVariable.Create(cx, symbol, ret, isVar, declLocation); + if (optionalSyntax != null) + TypeMention.Create(cx, optionalSyntax, parent, type); + }); return ret; } @@ -65,7 +70,7 @@ public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPat { var child0 = 0; foreach (var variable in designation.Variables) - switch(variable) + switch (variable) { case ParenthesizedVariableDesignationSyntax paren: CreateParenthesized(cx, varPattern, paren, tuple, child0++); @@ -97,7 +102,7 @@ public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPat static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { - switch(designation) + switch (designation) { case SingleVariableDesignationSyntax single: return CreateSingle(cx, node, single, parent, child); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs index db64d79ad8e4..f4a78353b5c2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs @@ -67,27 +67,23 @@ class CasePattern : Case private CasePattern(Context cx, CasePatternSwitchLabelSyntax node, Switch parent, int child) : base(cx, node, parent, child) { } - private void PopulatePattern(PatternSyntax pattern, TypeSyntax optionalType, SyntaxToken varKeyword, VariableDesignationSyntax designation) + private void PopulatePattern(PatternSyntax pattern, TypeSyntax optionalType, VariableDesignationSyntax designation) { var isVar = optionalType is null; - if (!isVar) - Expressions.TypeAccess.Create(cx, optionalType, this, 1); - switch (designation) { case SingleVariableDesignationSyntax _: 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)); - - Expressions.VariableDeclaration.Create(cx, symbol, type, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 0); + Expressions.VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 0); } break; case DiscardDesignationSyntax discard: - new Expressions.Discard(cx, discard, this, 0); + if (isVar) + new Expressions.Discard(cx, discard, this, 0); + else + Expressions.TypeAccess.Create(cx, optionalType, this, 0); break; case null: break; @@ -104,10 +100,10 @@ protected override void Populate() switch (Stmt.Pattern) { case VarPatternSyntax varPattern: - PopulatePattern(varPattern, null, varPattern.VarKeyword, varPattern.Designation); + PopulatePattern(varPattern, null, varPattern.Designation); break; case DeclarationPatternSyntax declarationPattern: - PopulatePattern(declarationPattern, declarationPattern.Type, default(SyntaxToken), declarationPattern.Designation); + PopulatePattern(declarationPattern, declarationPattern.Type, declarationPattern.Designation); break; case ConstantPatternSyntax pattern: Expression.Create(cx, pattern.Expression, this, 0); @@ -121,7 +117,7 @@ protected override void Populate() if (Stmt.WhenClause != null) { - Expression.Create(cx, Stmt.WhenClause.Condition, this, 2); + Expression.Create(cx, Stmt.WhenClause.Condition, this, 1); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index 2c3076757c26..e31f6336c138 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -27,8 +27,9 @@ protected override void Populate() var location = cx.Create(Stmt.Identifier.GetLocation()); if (typeSymbol.Name != "_") - Expressions.VariableDeclaration.Create(cx, typeSymbol, type, location, location, Stmt.Type.IsVar, this, 0); - TypeMention.Create(cx, Stmt.Type, this, type); + Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, location, Stmt.Type.IsVar, this, 0); + else + TypeMention.Create(cx, Stmt.Type, this, type); Statement.Create(cx, Stmt.Statement, this, 2); } diff --git a/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql b/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql index e347f1c8a27f..07a0233a156c 100644 --- a/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql +++ b/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql @@ -72,7 +72,8 @@ class ConstantNullnessCondition extends ConstantCondition { ConstantNullnessCondition() { forex(ControlFlow::Node cfn | cfn = this.getAControlFlowNode() | exists(ControlFlow::SuccessorTypes::NullnessSuccessor t, ControlFlow::Node s | - s = cfn.getASuccessorByType(t) | + s = cfn.getASuccessorByType(t) + | b = t.getValue() and not s.isJoin() ) and diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index aace6270c2fb..489dc14e9b6e 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -306,9 +306,8 @@ module AssignableInternal { /** A local variable declaration at the top-level of a pattern. */ class TopLevelPatternDecl extends LocalVariableDeclExpr { private PatternMatch pm; - TopLevelPatternDecl() { - this = pm.getPattern().(BindingPatternExpr).getVariableDeclExpr() - } + + TopLevelPatternDecl() { this = pm.getPattern().(BindingPatternExpr).getVariableDeclExpr() } PatternMatch getMatch() { result = pm } } diff --git a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll index 68547763f44c..d207557adbf0 100644 --- a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll @@ -19,17 +19,8 @@ predicate expr_parent_top_level_adjusted(Expr child, int i, @top_level_exprorstm } /** - * Holds if `case` statement `cs` is a type check of the form `case int _`, - * where `ta` is the type access `int`. - */ -private predicate discardTypeCaseStmt(CaseStmt cs, TypeAccess ta) { - expr_parent(ta, 1, cs) and - expr_parent(any(DiscardExpr de), 0, cs) -} - -/** - * The `expr_parent()` relation adjusted for expandable assignments, `is` expressions, - * and `case` statements. For example, the assignment `x += y` is extracted as + * The `expr_parent()` relation adjusted for expandable assignments. For example, + * the assignment `x += y` is extracted as * * ``` * += @@ -78,35 +69,7 @@ private predicate expr_parent_adjusted(Expr child, int i, ControlFlowElement par not ao.hasExpandedAssignment() and expr_parent(child, i, parent) ) - else - if parent instanceof IsExpr - then - i = 0 and - expr_parent(child, i, parent) - or - // e.g. `x is string s` or `x is null` - i = 1 and - expr_parent(child, any(int j | j in [2 .. 3]), parent) - or - // e.g. `x is string` - i = 1 and - not expr_parent(_, any(int j | j in [2 .. 3]), parent) and - expr_parent(child, i, parent) - else - if parent instanceof CaseStmt - then - // e.g. `case string s:` or `case 5:` - i = 0 and - expr_parent(child, i, parent) and - not discardTypeCaseStmt(parent, _) - or - // e.g. `case string _` - i = 0 and - discardTypeCaseStmt(parent, child) - or - i = 1 and - expr_parent(child, 2, parent) - else expr_parent(child, i, parent) + else expr_parent(child, i, parent) } /** diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll index ee85d9cb2805..a71195b776c7 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll @@ -417,9 +417,7 @@ predicate switchMatching(Switch s, Case c, PatternExpr pe) { pe = c.getPattern() } -private predicate mustHaveMatchingCompletion(Switch s, PatternExpr pe) { - switchMatching(s, _, pe) -} +private predicate mustHaveMatchingCompletion(Switch s, PatternExpr pe) { switchMatching(s, _, pe) } /** * Holds if a normal completion of `cfe` must be a matching completion. Thats is, diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index 06ea66a5f7a4..be3c0290132b 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -313,6 +313,7 @@ class ConstantPatternExpr extends PatternExpr { */ class TypePatternExpr extends PatternExpr { private Type t; + TypePatternExpr() { t = this.(TypeAccess).getTarget() or t = this.(LocalVariableDeclExpr).getVariable().getType() @@ -517,7 +518,7 @@ class Case extends PatternMatch, @case { /** * Gets the `when` expression of this case, if any. For example, `s.Length < 10` * in `string s when s.Length < 10 => s` - */ + */ Expr getCondition() { none() } /** Gets the body of this `case`. */ diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index d71e2ffde2fb..d1543f3920a3 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -1241,11 +1241,9 @@ | 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 ...: | Switch.cs:48:13:48:23 | case ...: | | Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:48:18:48:20 | access to type 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 ...: | Switch.cs:50:13:50:39 | case ...: | | Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:18:50:21 | access to type 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 | @@ -1267,7 +1265,6 @@ | 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 ...: | Switch.cs:70:13:70:24 | case ...: | | Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:18:70:20 | access to type 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 | "" | @@ -1295,7 +1292,6 @@ | 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 ...: | Switch.cs:95:13:95:24 | case ...: | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type 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 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index 82b3fa26268d..dac67a0c2220 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -1588,14 +1588,12 @@ | Switch.cs:48:13:48:23 | case ...: | Switch.cs:49:17:49:22 | break; | break | | Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:48:18:48:20 | access to type Int32 | match | | Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:48:18:48:20 | access to type Int32 | no-match | -| 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 ...: | Switch.cs:50:18:50:21 | access to type Boolean | no-match | | Switch.cs:50:13:50:39 | case ...: | Switch.cs:50:30:50:38 | ... != ... | false/false | | Switch.cs:50:13:50:39 | case ...: | Switch.cs:51:17:51:22 | break; | break | | Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:18:50:21 | access to type Boolean | match | | Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:18:50:21 | access to type Boolean | no-match | -| 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 | @@ -1626,7 +1624,6 @@ | Switch.cs:70:13:70:24 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | no-match | | Switch.cs:70:13:70:24 | case ...: | Switch.cs:71:15:71:20 | break; | break | | Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:18:70:20 | access to type Int32 | no-match | -| 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 | @@ -1672,7 +1669,6 @@ | Switch.cs:95:13:95:24 | case ...: | Switch.cs:96:15:96:26 | return ...; | return | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 | match | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 | no-match | -| 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 | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected index 28191f68ec9f..00053c4fe8e5 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected @@ -168,20 +168,20 @@ | Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:13:268:41 | call to operator == | Guards.cs:268:13:268:14 | access to parameter o1 | true | | Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:16:268:25 | call to method GetType | Guards.cs:268:13:268:14 | access to parameter o1 | non-null | | Guards.cs:271:11:271:12 | access to parameter o1 | Guards.cs:270:13:270:42 | call to operator == | Guards.cs:270:13:270:14 | access to parameter o1 | true | -| Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match Action a | +| Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match access to type Action | | Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match "" | -| Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | +| Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match null | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match "" | -| Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | +| Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | null | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match "" | -| Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | +| Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match null | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index 5a59ee7ea595..711cf7785213 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -168,20 +168,20 @@ | Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:13:268:41 | call to operator == | Guards.cs:268:13:268:14 | access to parameter o1 | true | | Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:16:268:25 | call to method GetType | Guards.cs:268:13:268:14 | access to parameter o1 | non-null | | Guards.cs:271:11:271:12 | access to parameter o1 | Guards.cs:270:13:270:42 | call to operator == | Guards.cs:270:13:270:14 | access to parameter o1 | true | -| Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match Action a | +| Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match access to type Action | | Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match "" | -| Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | +| Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | match null | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match "" | -| Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | +| Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | null | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match "" | -| Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match Action a | +| Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match null | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Splitting.cs:13:17:13:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs index 404e179b3a90..c81cc67c27c4 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs @@ -275,7 +275,7 @@ string M23(object o) { return o switch { - Action a => + Action _ => o.ToString(), // null guarded Action a => a.ToString(), // not null (but not a guard) diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 05cdb7319eec..c2274d5508db 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -350,8 +350,8 @@ | Guards.cs:270:16:270:25 | call to method GetType | non-null | Guards.cs:270:13:270:14 | access to parameter o1 | non-null | | Guards.cs:270:33:270:42 | call to method GetType | non-null | Guards.cs:270:30:270:31 | access to parameter o2 | non-null | | Guards.cs:276:16:276:16 | access to parameter o | match "" | Guards.cs:276:16:276:16 | access to parameter o | non-null | -| Guards.cs:276:16:276:16 | access to parameter o | match Action a | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:276:16:276:16 | access to parameter o | match Action a | Guards.cs:276:16:276:16 | access to parameter o | non-null | +| Guards.cs:276:16:276:16 | access to parameter o | match access to type Action | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:276:16:276:16 | access to parameter o | match null | Guards.cs:276:16:276:16 | access to parameter o | null | | Guards.cs:276:16:276:16 | access to parameter o | non-match null | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:281:17:281:17 | access to local variable a | non-null | Guards.cs:276:16:276:16 | access to parameter o | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/MatchingGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/MatchingGuardedExpr.expected index 8d901cb09eaf..d74c6339eb79 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/MatchingGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/MatchingGuardedExpr.expected @@ -10,15 +10,15 @@ | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:155:13:155:34 | case ...: | non-match Action a | false | | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:157:13:157:20 | case ...: | non-match "" | false | | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:159:13:159:22 | case ...: | non-match null | false | -| Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | match Action a | true | -| Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | non-match Action a | false | +| Guards.cs:279:17:279:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | match access to type Action | true | +| Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | non-match access to type Action | false | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:280:13:281:28 | ... => ... | non-match Action a | false | | Guards.cs:283:17:283:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:282:13:283:28 | ... => ... | match "" | true | -| Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | non-match Action a | false | +| Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | non-match access to type Action | false | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:280:13:281:28 | ... => ... | non-match Action a | false | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:282:13:283:28 | ... => ... | non-match "" | false | | Guards.cs:285:17:285:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:284:13:285:28 | ... => ... | match null | true | -| Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | non-match Action a | false | +| Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:278:13:279:28 | ... => ... | non-match access to type Action | false | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:280:13:281:28 | ... => ... | non-match Action a | false | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:282:13:283:28 | ... => ... | non-match "" | false | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:284:13:285:28 | ... => ... | non-match null | false | diff --git a/csharp/ql/test/library-tests/csharp7/Discards.expected b/csharp/ql/test/library-tests/csharp7/Discards.expected index 6bc6b40aa71e..41f6e47ac17e 100644 --- a/csharp/ql/test/library-tests/csharp7/Discards.expected +++ b/csharp/ql/test/library-tests/csharp7/Discards.expected @@ -6,4 +6,3 @@ | 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 | diff --git a/csharp/ql/test/library-tests/csharp7/TypeCase2.ql b/csharp/ql/test/library-tests/csharp7/TypeCase2.ql index 7d86470709a1..3d2d5e7981d3 100644 --- a/csharp/ql/test/library-tests/csharp7/TypeCase2.ql +++ b/csharp/ql/test/library-tests/csharp7/TypeCase2.ql @@ -1,6 +1,7 @@ import csharp from Case c, boolean isVar, VariablePatternExpr vpe -where vpe = c.getPattern() and - if vpe.isImplicitlyTyped() then isVar = true else isVar = false +where + vpe = c.getPattern() and + if vpe.isImplicitlyTyped() then isVar = true else isVar = false select c, vpe, vpe.getType().toString(), isVar diff --git a/csharp/ql/test/library-tests/csharp8/patterns.cs b/csharp/ql/test/library-tests/csharp8/patterns.cs index 36aeb1a18912..f2de7a1dad77 100644 --- a/csharp/ql/test/library-tests/csharp8/patterns.cs +++ b/csharp/ql/test/library-tests/csharp8/patterns.cs @@ -137,7 +137,9 @@ void Expressions2(object o) { 1 => throw new ArgumentException(), 2 => 3, - object y when y is {} => 4 + object y when y is {} => 4, + string _ => 5, + MyStruct { X: 10 } _ => 6 }; } catch(InvalidOperationException ex) diff --git a/csharp/ql/test/library-tests/csharp8/patterns.expected b/csharp/ql/test/library-tests/csharp8/patterns.expected index 09ea3fd68c93..87ae263997e3 100644 --- a/csharp/ql/test/library-tests/csharp8/patterns.expected +++ b/csharp/ql/test/library-tests/csharp8/patterns.expected @@ -3,7 +3,7 @@ switchExprs | 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 | access to parameter o | +| patterns.cs:136:17:143:13 | ... switch { ... } | patterns.cs:136:17:136:17 | access to parameter o | 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" | @@ -19,6 +19,8 @@ switchExprCases | 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 | +| patterns.cs:141:17:141:29 | ... => ... | patterns.cs:141:17:141:22 | access to type String | patterns.cs:141:29:141:29 | 5 | +| patterns.cs:142:17:142:41 | ... => ... | patterns.cs:142:17:142:36 | { ... } | patterns.cs:142:41:142:41 | 6 | 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 | ... > ... | @@ -39,6 +41,7 @@ propertyPatterns | patterns.cs:128:22:128:33 | { ... } | | patterns.cs:129:22:129:30 | { ... } | | patterns.cs:140:36:140:37 | { ... } | +| patterns.cs:142:26:142:34 | { ... } | 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 | @@ -54,6 +57,7 @@ propertyPatternChild | 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 | +| patterns.cs:142:26:142:34 | { ... } | 0 | patterns.cs:142:31:142:32 | 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 | @@ -145,6 +149,7 @@ recursivePatterns | patterns.cs:129:13:129:33 | { ... } | | patterns.cs:130:13:130:18 | { ... } | | patterns.cs:140:36:140:37 | { ... } | +| patterns.cs:142:17:142:36 | { ... } | discards | patterns.cs:27:51:27:51 | _ | | patterns.cs:94:22:94:22 | _ | @@ -181,3 +186,4 @@ labeledPatternExpr | patterns.cs:70:32:70:33 | 10 | X | | patterns.cs:128:27:128:31 | Int32 x | X | | patterns.cs:129:27:129:28 | 10 | X | +| patterns.cs:142:31:142:32 | 10 | X | diff --git a/csharp/ql/test/library-tests/csharp8/patterns.ql b/csharp/ql/test/library-tests/csharp8/patterns.ql index cf49ebc9e4ce..0a726c6bd496 100644 --- a/csharp/ql/test/library-tests/csharp8/patterns.ql +++ b/csharp/ql/test/library-tests/csharp8/patterns.ql @@ -66,6 +66,4 @@ query predicate isRecursivePatternExprWithDecl( decl = expr.getRecursivePattern().getVariableDeclExpr() } -query predicate labeledPatternExpr(LabeledPatternExpr e, string s) { - s = e.getLabel() -} +query predicate labeledPatternExpr(LabeledPatternExpr e, string s) { s = e.getLabel() } diff --git a/csharp/ql/test/library-tests/csharp8/ranges.ql b/csharp/ql/test/library-tests/csharp8/ranges.ql index e6a9bf454f24..9cd0c8868d63 100644 --- a/csharp/ql/test/library-tests/csharp8/ranges.ql +++ b/csharp/ql/test/library-tests/csharp8/ranges.ql @@ -11,7 +11,7 @@ Expr stripConversions(Expr expr) { if getConversion(expr, _) then getConversion(expr, result) else result = expr } -query predicate indexes(IndexExpr e, Expr c) { c = e.getExpr() } +query predicate indexes(IndexExpr e, Expr c) { c = e.getExpr() } query predicate ranges(RangeExpr e) { any() } diff --git a/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected b/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected index 87e546641bef..2f667b54767f 100644 --- a/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected +++ b/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected @@ -81,8 +81,8 @@ | 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:123:10:123:21 | enter Expressions2 | patterns.cs:124:5:149:5 | {...} | semmle.label | successor | +| patterns.cs:124:5:149: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 | @@ -90,7 +90,7 @@ | 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:13:132:9 | Int32 r = ... | patterns.cs:134:9:148: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 | @@ -123,38 +123,48 @@ | 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:134:9:148:9 | try {...} ... | patterns.cs:135:9:144:9 | {...} | semmle.label | successor | +| patterns.cs:135:9:144:9 | {...} | patterns.cs:136:13:143:14 | ...; | semmle.label | successor | +| patterns.cs:136:13:143:13 | ... = ... | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | successor | +| patterns.cs:136:13:143:14 | ...; | patterns.cs:136:17:143:13 | ... switch { ... } | semmle.label | successor | | patterns.cs:136:17:136:17 | access to parameter o | patterns.cs:138:17:138:50 | ... => ... | semmle.label | successor | -| patterns.cs:136:17:141:13 | ... switch { ... } | patterns.cs:136:17:136:17 | access to parameter o | semmle.label | successor | +| patterns.cs:136:17:143:13 | ... switch { ... } | patterns.cs:136:17:136:17 | access to parameter o | 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:22:138:50 | throw ... | patterns.cs:145:9:148: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:138:28:138:50 | object creation of type ArgumentException | patterns.cs:145:9:148: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:139:22:139:22 | 3 | patterns.cs:136:13:143: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:24 | Object y | patterns.cs:141:17:141:29 | ... => ... | semmle.label | no-match | | 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:31:140:37 | ... is ... | patterns.cs:141:17:141:29 | ... => ... | semmle.label | false | | 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 | +| patterns.cs:140:42:140:42 | 4 | patterns.cs:136:13:143:13 | ... = ... | semmle.label | successor | +| patterns.cs:141:17:141:22 | access to type String | patterns.cs:141:29:141:29 | 5 | semmle.label | match | +| patterns.cs:141:17:141:22 | access to type String | patterns.cs:142:17:142:41 | ... => ... | semmle.label | no-match | +| patterns.cs:141:17:141:29 | ... => ... | patterns.cs:141:17:141:22 | access to type String | semmle.label | successor | +| patterns.cs:141:29:141:29 | 5 | patterns.cs:136:13:143:13 | ... = ... | semmle.label | successor | +| patterns.cs:142:17:142:36 | { ... } | patterns.cs:142:41:142:41 | 6 | semmle.label | match | +| patterns.cs:142:17:142:36 | { ... } | patterns.cs:145:9:148:9 | [exception: InvalidOperationException] catch (...) {...} | semmle.label | exception(InvalidOperationException) | +| patterns.cs:142:17:142:41 | ... => ... | patterns.cs:142:31:142:32 | 10 | semmle.label | successor | +| patterns.cs:142:26:142:34 | { ... } | patterns.cs:142:17:142:36 | { ... } | semmle.label | successor | +| patterns.cs:142:31:142:32 | 10 | patterns.cs:142:26:142:34 | { ... } | semmle.label | successor | +| patterns.cs:142:41:142:41 | 6 | patterns.cs:136:13:143:13 | ... = ... | semmle.label | successor | +| patterns.cs:145:9:148:9 | [exception: ArgumentException] catch (...) {...} | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | exception(ArgumentException) | +| patterns.cs:145:9:148:9 | [exception: Exception] catch (...) {...} | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | exception(Exception) | +| patterns.cs:145:9:148:9 | [exception: Exception] catch (...) {...} | patterns.cs:145:41:145:42 | [exception: Exception] InvalidOperationException ex | semmle.label | match | +| patterns.cs:145:9:148:9 | [exception: InvalidOperationException] catch (...) {...} | patterns.cs:145:41:145:42 | [exception: InvalidOperationException] InvalidOperationException ex | semmle.label | match | +| patterns.cs:145:41:145:42 | [exception: Exception] InvalidOperationException ex | patterns.cs:146:9:148:9 | {...} | semmle.label | successor | +| patterns.cs:145:41:145:42 | [exception: InvalidOperationException] InvalidOperationException ex | patterns.cs:146:9:148:9 | {...} | semmle.label | successor | +| patterns.cs:146:9:148:9 | {...} | patterns.cs:147:13:147:51 | ...; | semmle.label | successor | +| patterns.cs:147:13:147:50 | call to method WriteLine | patterns.cs:123:10:123:21 | exit Expressions2 | semmle.label | successor | +| patterns.cs:147:13:147:51 | ...; | patterns.cs:147:31:147:49 | "Invalid operation" | semmle.label | successor | +| patterns.cs:147:31:147:49 | "Invalid operation" | patterns.cs:147:13:147:50 | call to method WriteLine | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.ql b/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.ql index c0a320803ca4..f5815998200c 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.ql +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.ql @@ -1,6 +1,8 @@ import csharp -from string inout, Ssa::ExplicitDefinition def, Ssa::Definition targetDef, ControlFlow::Node call, boolean additionalCalls +from + string inout, Ssa::ExplicitDefinition def, Ssa::Definition targetDef, ControlFlow::Node call, + boolean additionalCalls where inout = "in" and def.isCapturedVariableDefinitionFlowIn(targetDef, call, additionalCalls) or diff --git a/csharp/upgrades/57331d90231fc8247d5a5197f4ac45d502708c6a/expr_parent.ql b/csharp/upgrades/57331d90231fc8247d5a5197f4ac45d502708c6a/expr_parent.ql new file mode 100644 index 000000000000..26cec97398fa --- /dev/null +++ b/csharp/upgrades/57331d90231fc8247d5a5197f4ac45d502708c6a/expr_parent.ql @@ -0,0 +1,47 @@ +class Expr extends @expr { + string toString() { none() } +} + +class ControlFlowElement extends @control_flow_element { + string toString() { none() } +} + +private predicate discardTypeCaseStmt(@case cs, @type_access_expr ta) { + expr_parent(ta, 1, cs) and + expr_parent(any(@discard_expr de), 0, cs) +} + +private predicate expr_parent_adjusted(Expr child, int i, ControlFlowElement parent) { + if parent instanceof @is_expr + then + i = 0 and + expr_parent(child, i, parent) + or + // e.g. `x is string s` or `x is null` + i = 1 and + expr_parent(child, any(int j | j in [2 .. 3]), parent) + or + // e.g. `x is string` + i = 1 and + not expr_parent(_, any(int j | j in [2 .. 3]), parent) and + expr_parent(child, i, parent) + else + if parent instanceof @case + then + // e.g. `case string s:` or `case 5:` + i = 0 and + expr_parent(child, i, parent) and + not discardTypeCaseStmt(parent, _) + or + // e.g. `case string _` + i = 0 and + discardTypeCaseStmt(parent, child) + or + i = 1 and + expr_parent(child, 2, parent) + else expr_parent(child, i, parent) +} + +from Expr child, int i, ControlFlowElement parent +where expr_parent_adjusted(child, i, parent) +select child, i, parent diff --git a/csharp/upgrades/57331d90231fc8247d5a5197f4ac45d502708c6a/upgrade.properties b/csharp/upgrades/57331d90231fc8247d5a5197f4ac45d502708c6a/upgrade.properties index 3b3e6bd45643..1afe9e4f31cd 100644 --- a/csharp/upgrades/57331d90231fc8247d5a5197f4ac45d502708c6a/upgrade.properties +++ b/csharp/upgrades/57331d90231fc8247d5a5197f4ac45d502708c6a/upgrade.properties @@ -1,2 +1,4 @@ description: Add C#8 expression and union types supporting ranges, recursive patterns and switch expressions. compatibility: backwards + +expr_parent.rel: run expr_parent.qlo \ No newline at end of file