mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge pull request #3473 from aschackmull/java/switchexpr
Java: Extend library support for switch expressions.
This commit is contained in:
@@ -579,6 +579,8 @@ private module ControlFlowGraphImpl {
|
||||
n instanceof Stmt and
|
||||
not n instanceof PostOrderNode and
|
||||
not n instanceof SynchronizedStmt
|
||||
or
|
||||
result = n and n instanceof SwitchExpr
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1051,6 +1051,18 @@ class MemberRefExpr extends FunctionalExpr, @memberref {
|
||||
override string toString() { result = "...::..." }
|
||||
}
|
||||
|
||||
/** A conditional expression or a `switch` expression. */
|
||||
class ChooseExpr extends Expr {
|
||||
ChooseExpr() { this instanceof ConditionalExpr or this instanceof SwitchExpr }
|
||||
|
||||
/** Gets a result expression of this `switch` or conditional expression. */
|
||||
Expr getAResultExpr() {
|
||||
result = this.(ConditionalExpr).getTrueExpr() or
|
||||
result = this.(ConditionalExpr).getFalseExpr() or
|
||||
result = this.(SwitchExpr).getAResult()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A conditional expression of the form `a ? b : c`, where `a` is the condition,
|
||||
* `b` is the expression that is evaluated if the condition evaluates to `true`,
|
||||
|
||||
@@ -248,8 +248,7 @@ private predicate formatStringFragment(Expr fmt) {
|
||||
e.(VarAccess).getVariable().getAnAssignedValue() = fmt or
|
||||
e.(AddExpr).getLeftOperand() = fmt or
|
||||
e.(AddExpr).getRightOperand() = fmt or
|
||||
e.(ConditionalExpr).getTrueExpr() = fmt or
|
||||
e.(ConditionalExpr).getFalseExpr() = fmt
|
||||
e.(ChooseExpr).getAResultExpr() = fmt
|
||||
)
|
||||
}
|
||||
|
||||
@@ -293,9 +292,7 @@ private predicate formatStringValue(Expr e, string fmtvalue) {
|
||||
fmtvalue = left + right
|
||||
)
|
||||
or
|
||||
formatStringValue(e.(ConditionalExpr).getTrueExpr(), fmtvalue)
|
||||
or
|
||||
formatStringValue(e.(ConditionalExpr).getFalseExpr(), fmtvalue)
|
||||
formatStringValue(e.(ChooseExpr).getAResultExpr(), fmtvalue)
|
||||
or
|
||||
exists(Method getprop, MethodAccess ma, string prop |
|
||||
e = ma and
|
||||
|
||||
@@ -213,7 +213,7 @@ private predicate hasPossibleUnknownValue(SsaVariable v) {
|
||||
|
||||
/**
|
||||
* Gets a sub-expression of `e` whose value can flow to `e` through
|
||||
* `ConditionalExpr`s. Parentheses are also removed.
|
||||
* `ConditionalExpr`s.
|
||||
*/
|
||||
private Expr possibleValue(Expr e) {
|
||||
result = possibleValue(e.(ConditionalExpr).getTrueExpr())
|
||||
|
||||
@@ -10,8 +10,7 @@ private import RangeAnalysis
|
||||
/** Gets an expression that might have the value `i`. */
|
||||
private Expr exprWithIntValue(int i) {
|
||||
result.(ConstantIntegerExpr).getIntValue() = i or
|
||||
result.(ConditionalExpr).getTrueExpr() = exprWithIntValue(i) or
|
||||
result.(ConditionalExpr).getFalseExpr() = exprWithIntValue(i)
|
||||
result.(ChooseExpr).getAResultExpr() = exprWithIntValue(i)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,8 +45,7 @@ private import semmle.code.java.frameworks.Assertions
|
||||
/** Gets an expression that may be `null`. */
|
||||
Expr nullExpr() {
|
||||
result instanceof NullLiteral or
|
||||
result.(ConditionalExpr).getTrueExpr() = nullExpr() or
|
||||
result.(ConditionalExpr).getFalseExpr() = nullExpr() or
|
||||
result.(ChooseExpr).getAResultExpr() = nullExpr() or
|
||||
result.(AssignExpr).getSource() = nullExpr() or
|
||||
result.(CastExpr).getExpr() = nullExpr()
|
||||
}
|
||||
@@ -81,9 +80,7 @@ private predicate unboxed(Expr e) {
|
||||
or
|
||||
exists(UnaryExpr un | un.getExpr() = e)
|
||||
or
|
||||
exists(ConditionalExpr cond | cond.getType() instanceof PrimitiveType |
|
||||
cond.getTrueExpr() = e or cond.getFalseExpr() = e
|
||||
)
|
||||
exists(ChooseExpr cond | cond.getType() instanceof PrimitiveType | cond.getAResultExpr() = e)
|
||||
or
|
||||
exists(ConditionNode cond | cond.getCondition() = e)
|
||||
or
|
||||
|
||||
@@ -552,9 +552,7 @@ private Sign exprSign(Expr e) {
|
||||
result = s1.urshift(s2)
|
||||
)
|
||||
or
|
||||
result = exprSign(e.(ConditionalExpr).getTrueExpr())
|
||||
or
|
||||
result = exprSign(e.(ConditionalExpr).getFalseExpr())
|
||||
result = exprSign(e.(ChooseExpr).getAResultExpr())
|
||||
or
|
||||
result = exprSign(e.(CastExpr).getExpr())
|
||||
)
|
||||
|
||||
@@ -72,9 +72,7 @@ private predicate privateParamArg(Parameter p, Argument arg) {
|
||||
* necessarily functionally determined by `n2`.
|
||||
*/
|
||||
private predicate joinStep0(TypeFlowNode n1, TypeFlowNode n2) {
|
||||
n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr()
|
||||
n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr()
|
||||
or
|
||||
exists(Field f, Expr e |
|
||||
f = n2.asField() and
|
||||
@@ -226,9 +224,8 @@ private predicate upcastCand(TypeFlowNode n, RefType t, RefType t1, RefType t2)
|
||||
or
|
||||
exists(Parameter p | privateParamArg(p, n.asExpr()) and t2 = p.getType().getErasure())
|
||||
or
|
||||
exists(ConditionalExpr cond |
|
||||
cond.getTrueExpr() = n.asExpr() or cond.getFalseExpr() = n.asExpr()
|
||||
|
|
||||
exists(ChooseExpr cond |
|
||||
cond.getAResultExpr() = n.asExpr() and
|
||||
t2 = cond.getType().getErasure()
|
||||
)
|
||||
)
|
||||
|
||||
@@ -397,9 +397,7 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||
or
|
||||
node2.asExpr().(CastExpr).getExpr() = node1.asExpr()
|
||||
or
|
||||
node2.asExpr().(ConditionalExpr).getTrueExpr() = node1.asExpr()
|
||||
or
|
||||
node2.asExpr().(ConditionalExpr).getFalseExpr() = node1.asExpr()
|
||||
node2.asExpr().(ChooseExpr).getAResultExpr() = node1.asExpr()
|
||||
or
|
||||
node2.asExpr().(AssignExpr).getSource() = node1.asExpr()
|
||||
}
|
||||
|
||||
@@ -202,9 +202,7 @@ private predicate flowStep(RelevantNode n1, RelevantNode n2) {
|
||||
or
|
||||
n2.asExpr().(CastExpr).getExpr() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr()
|
||||
n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(AssignExpr).getSource() = n1.asExpr()
|
||||
or
|
||||
|
||||
@@ -100,9 +100,7 @@ private predicate step(Node n1, Node n2) {
|
||||
or
|
||||
n2.asExpr().(CastExpr).getExpr() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr()
|
||||
n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(AssignExpr).getSource() = n1.asExpr()
|
||||
or
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
class TestSwitchExpr {
|
||||
Object source() { return new Object(); }
|
||||
|
||||
void sink(Object o) { }
|
||||
|
||||
void test(String s) {
|
||||
Object x1 = source();
|
||||
Object x2 = switch (s) {
|
||||
case "a", "b", ("a" + "b") -> null;
|
||||
default -> x1;
|
||||
};
|
||||
Object x3 = switch (s) {
|
||||
case "c", "d" -> { yield x2; }
|
||||
default -> throw new RuntimeException();
|
||||
};
|
||||
Object x4 = switch (s) {
|
||||
case "a", "b":
|
||||
case "c", "d", ("c" + "d"):
|
||||
yield x3;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
};
|
||||
sink(x4);
|
||||
}
|
||||
}
|
||||
1
java/ql/test/library-tests/dataflow/switchexpr/options
Normal file
1
java/ql/test/library-tests/dataflow/switchexpr/options
Normal file
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -source 14 -target 14
|
||||
@@ -0,0 +1,9 @@
|
||||
| TestSwitchExpr.java:4:15:4:22 | o |
|
||||
| TestSwitchExpr.java:7:21:7:28 | source(...) |
|
||||
| TestSwitchExpr.java:8:21:8:30 | switch (...) |
|
||||
| TestSwitchExpr.java:10:24:10:25 | x1 |
|
||||
| TestSwitchExpr.java:12:21:12:30 | switch (...) |
|
||||
| TestSwitchExpr.java:13:38:13:39 | x2 |
|
||||
| TestSwitchExpr.java:16:21:16:30 | switch (...) |
|
||||
| TestSwitchExpr.java:19:23:19:24 | x3 |
|
||||
| TestSwitchExpr.java:23:14:23:15 | x4 |
|
||||
@@ -0,0 +1,15 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "qqconf" }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("source") }
|
||||
|
||||
override predicate isSink(Node n) { any() }
|
||||
}
|
||||
|
||||
from Conf c, Node sink
|
||||
where c.hasFlow(_, sink)
|
||||
select sink
|
||||
Reference in New Issue
Block a user