From 7dd4030f51a804be71db7639b7b5a72a9197018a Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 26 Oct 2023 16:21:48 +0100 Subject: [PATCH] Pattern cases: support type-flow --- .../lib/semmle/code/java/dataflow/TypeFlow.qll | 18 +++++++++++++++++- .../library-tests/typeflow/UnionTypes.java | 4 ++++ .../library-tests/typeflow/typeflow.expected | 1 + .../typeflow/uniontypeflow.expected | 11 ++++++++--- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll index c4b95645bc8..acf704b3722 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll @@ -440,6 +440,21 @@ predicate arrayInstanceOfGuarded(ArrayAccess aa, RefType t) { ) } +/** + * Holds if `va` is an access to a value that is guarded by `case T t`. + */ +private predicate patternCaseGuarded(VarAccess va, RefType t) { + exists(PatternCase pc, BaseSsaVariable v | + va = v.getAUse() and + ( + pc.getSwitch().getExpr() = v.getAUse() or + pc.getSwitchExpr().getExpr() = v.getAUse() + ) and + pc.getDecl().getBasicBlock().bbDominates(va.getBasicBlock()) and + t = pc.getDecl().getType() + ) +} + /** * Holds if `t` is the type of the `this` value corresponding to the the * `SuperAccess`. As the `SuperAccess` expression has the type of the supertype, @@ -465,7 +480,8 @@ private predicate typeFlowBaseCand(TypeFlowNode n, RefType t) { instanceOfGuarded(n.asExpr(), srctype) or arrayInstanceOfGuarded(n.asExpr(), srctype) or n.asExpr().(FunctionalExpr).getConstructedType() = srctype or - superAccess(n.asExpr(), srctype) + superAccess(n.asExpr(), srctype) or + patternCaseGuarded(n.asExpr(), srctype) | t = srctype.(BoundedType).getAnUltimateUpperBoundType() or diff --git a/java/ql/test/library-tests/typeflow/UnionTypes.java b/java/ql/test/library-tests/typeflow/UnionTypes.java index a82b3828d2f..44fb54336c6 100644 --- a/java/ql/test/library-tests/typeflow/UnionTypes.java +++ b/java/ql/test/library-tests/typeflow/UnionTypes.java @@ -44,6 +44,10 @@ public class UnionTypes { if (x instanceof Inter) { x.hashCode(); } + var hashCode = switch (x) { + case Inter i -> x.hashCode(); + default -> 0; + }; } void m3(Object d) { diff --git a/java/ql/test/library-tests/typeflow/typeflow.expected b/java/ql/test/library-tests/typeflow/typeflow.expected index 021d04b55d3..0e4f3c9ff74 100644 --- a/java/ql/test/library-tests/typeflow/typeflow.expected +++ b/java/ql/test/library-tests/typeflow/typeflow.expected @@ -14,3 +14,4 @@ | A.java:70:23:70:24 | x2 | Integer | false | | A.java:92:18:92:18 | n | Integer | false | | UnionTypes.java:45:7:45:7 | x | Inter | false | +| UnionTypes.java:48:23:48:23 | x | Inter | false | diff --git a/java/ql/test/library-tests/typeflow/uniontypeflow.expected b/java/ql/test/library-tests/typeflow/uniontypeflow.expected index 7c595175301..c203583249d 100644 --- a/java/ql/test/library-tests/typeflow/uniontypeflow.expected +++ b/java/ql/test/library-tests/typeflow/uniontypeflow.expected @@ -19,6 +19,11 @@ | UnionTypes.java:44:9:44:9 | x | 3 | A3 | false | | UnionTypes.java:45:7:45:7 | x | 2 | A1 | false | | UnionTypes.java:45:7:45:7 | x | 2 | A2 | true | -| UnionTypes.java:51:7:51:7 | d | 3 | A1 | false | -| UnionTypes.java:51:7:51:7 | d | 3 | A2 | false | -| UnionTypes.java:51:7:51:7 | d | 3 | A3 | false | +| UnionTypes.java:47:28:47:28 | x | 3 | A1 | false | +| UnionTypes.java:47:28:47:28 | x | 3 | A2 | true | +| UnionTypes.java:47:28:47:28 | x | 3 | A3 | false | +| UnionTypes.java:48:23:48:23 | x | 2 | A1 | false | +| UnionTypes.java:48:23:48:23 | x | 2 | A2 | true | +| UnionTypes.java:55:7:55:7 | d | 3 | A1 | false | +| UnionTypes.java:55:7:55:7 | d | 3 | A2 | false | +| UnionTypes.java:55:7:55:7 | d | 3 | A3 | false |