Merge pull request #3473 from aschackmull/java/switchexpr

Java: Extend library support for switch expressions.
This commit is contained in:
yo-h
2020-05-15 20:46:37 -04:00
committed by GitHub
15 changed files with 77 additions and 31 deletions

View File

@@ -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
}
/**

View File

@@ -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`,

View File

@@ -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

View File

@@ -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())

View File

@@ -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)
}
/**

View File

@@ -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

View File

@@ -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())
)

View File

@@ -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()
)
)

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -source 14 -target 14

View File

@@ -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 |

View File

@@ -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