diff --git a/java/ql/src/semmle/code/java/Statement.qll b/java/ql/src/semmle/code/java/Statement.qll index e3e3f3e79764..2f98615b2436 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -423,6 +423,14 @@ class SwitchCase extends Stmt, @case { */ SwitchExpr getSwitchExpr() { result.getACase() = this } + /** + * Gets the expression of the surrounding switch that this case is compared + * against. + */ + Expr getSelectorExpr() { + result = this.getSwitch().getExpr() or result = this.getSwitchExpr().getExpr() + } + /** * PREVIEW FEATURE in Java 12. Subject to removal in a future release. * @@ -625,7 +633,10 @@ class BreakStmt extends Stmt, @breakstmt { override string pp() { if this.hasLabel() then result = "break " + this.getLabel() - else if this.hasValue() then result = "break ..." else result = "break" + else + if this.hasValue() + then result = "break ..." + else result = "break" } /** This statement's Halstead ID (used to compute Halstead metrics). */ diff --git a/java/ql/src/semmle/code/java/controlflow/Guards.qll b/java/ql/src/semmle/code/java/controlflow/Guards.qll index de05b1214331..ac7d4cb81504 100644 --- a/java/ql/src/semmle/code/java/controlflow/Guards.qll +++ b/java/ql/src/semmle/code/java/controlflow/Guards.qll @@ -93,7 +93,8 @@ class Guard extends ExprParent { /** Gets the statement containing this guard. */ Stmt getEnclosingStmt() { result = this.(Expr).getEnclosingStmt() or - result = this.(SwitchCase).getSwitch() + result = this.(SwitchCase).getSwitch() or + result = this.(SwitchCase).getSwitchExpr().getEnclosingStmt() } /** @@ -126,7 +127,7 @@ class Guard extends ExprParent { branch = true and bb2.getFirstNode() = sc.getControlFlowNode() and pred = sc.getControlFlowNode().getAPredecessor() and - pred.(Expr).getParent*() = sc.getSwitch().getExpr() and + pred.(Expr).getParent*() = sc.getSelectorExpr() and bb1 = pred.getBasicBlock() ) or @@ -160,12 +161,12 @@ class Guard extends ExprParent { } private predicate switchCaseControls(SwitchCase sc, BasicBlock bb) { - exists(BasicBlock caseblock, SwitchStmt ss | - ss.getACase() = sc and + exists(BasicBlock caseblock, Expr selector | + selector = sc.getSelectorExpr() and caseblock.getFirstNode() = sc.getControlFlowNode() and caseblock.bbDominates(bb) and forall(ControlFlowNode pred | pred = sc.getControlFlowNode().getAPredecessor() | - pred.(Expr).getParent*() = ss.getExpr() + pred.(Expr).getParent*() = selector ) ) } @@ -254,7 +255,8 @@ private predicate equalityGuard(Guard g, Expr e1, Expr e2, boolean polarity) { exists(ConstCase cc | cc = g and polarity = true and - cc.getSwitch().getExpr().getProperExpr() = e1 and - cc.getValue() = e2 + cc.getSelectorExpr().getProperExpr() = e1 and + cc.getValue() = e2 and + strictcount(cc.getValue(_)) = 1 ) } diff --git a/java/ql/test/library-tests/guards12/Test.java b/java/ql/test/library-tests/guards12/Test.java new file mode 100644 index 000000000000..03ccc92d2459 --- /dev/null +++ b/java/ql/test/library-tests/guards12/Test.java @@ -0,0 +1,9 @@ +class Test { + void foo(String s) { + int x = switch(s) { + case "a", "b" -> 1; + case "c" -> 2; + default -> 3; + }; + } +} diff --git a/java/ql/test/library-tests/guards12/guard.expected b/java/ql/test/library-tests/guards12/guard.expected new file mode 100644 index 000000000000..d578ba1141d4 --- /dev/null +++ b/java/ql/test/library-tests/guards12/guard.expected @@ -0,0 +1 @@ +| Test.java:5:7:5:17 | stmt | Test.java:3:20:3:20 | s | Test.java:5:12:5:14 | "c" | true | true | Test.java:5:7:5:17 | stmt | diff --git a/java/ql/test/library-tests/guards12/guard.ql b/java/ql/test/library-tests/guards12/guard.ql new file mode 100644 index 000000000000..206e85f8bb8b --- /dev/null +++ b/java/ql/test/library-tests/guards12/guard.ql @@ -0,0 +1,8 @@ +import java +import semmle.code.java.controlflow.Guards + +from Guard g, BasicBlock bb, boolean branch, VarAccess e1, Expr e2, boolean pol +where + g.controls(bb, branch) and + g.isEquality(e1, e2, pol) +select g, e1, e2, pol, branch, bb diff --git a/java/ql/test/library-tests/guards12/options b/java/ql/test/library-tests/guards12/options new file mode 100644 index 000000000000..33d712034f91 --- /dev/null +++ b/java/ql/test/library-tests/guards12/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview -source 12 -target 12