mirror of
https://github.com/github/codeql.git
synced 2026-05-04 13:15:21 +02:00
Handle 'case null, default:'
This commit is contained in:
@@ -1514,7 +1514,8 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr {
|
||||
* which may be either a normal `case` or a `default`.
|
||||
*/
|
||||
SwitchCase getCase(int i) {
|
||||
result = rank[i + 1](SwitchCase case, int idx | case.isNthChildOf(this, idx) | case order by idx)
|
||||
result =
|
||||
rank[i + 1](SwitchCase case, int idx | case.isNthChildOf(this, idx) | case order by idx)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1532,6 +1533,9 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr {
|
||||
/** Gets the `default` case of this switch expression, if any. */
|
||||
DefaultCase getDefaultCase() { result = this.getACase() }
|
||||
|
||||
/** Gets the `default` or `case null, default` case of this switch statement, if any. */
|
||||
SwitchCase getDefaultOrNullDefaultCase() { result = this.getACase() and result.hasDefaultLabel() }
|
||||
|
||||
/** Gets the expression of this `switch` expression. */
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
@@ -1543,9 +1547,7 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr {
|
||||
}
|
||||
|
||||
/** Holds if this switch has a case handling a null literal. */
|
||||
predicate hasNullCase() {
|
||||
this.getAConstCase().getValue(_) instanceof NullLiteral
|
||||
}
|
||||
predicate hasNullCase() { this.getAConstCase().getValue(_) instanceof NullLiteral }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = "switch (...)" }
|
||||
@@ -1638,19 +1640,13 @@ class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr {
|
||||
string getName() { result = this.getVariable().getName() }
|
||||
|
||||
/** Gets the switch statement or expression whose pattern declares this identifier, if any. */
|
||||
StmtParent getAssociatedSwitch() {
|
||||
result = this.getParent().(PatternCase).getParent()
|
||||
}
|
||||
StmtParent getAssociatedSwitch() { result = this.getParent().(PatternCase).getParent() }
|
||||
|
||||
/** Holds if this is a declaration stemming from a pattern switch case. */
|
||||
predicate hasAssociatedSwitch() {
|
||||
exists(this.getAssociatedSwitch())
|
||||
}
|
||||
predicate hasAssociatedSwitch() { exists(this.getAssociatedSwitch()) }
|
||||
|
||||
/** Gets the initializer expression of this local variable declaration expression, if any. */
|
||||
Expr getInit() {
|
||||
result.isNthChildOf(this, 0)
|
||||
}
|
||||
Expr getInit() { result.isNthChildOf(this, 0) }
|
||||
|
||||
/** Holds if this variable declaration implicitly initializes the variable. */
|
||||
predicate hasImplicitInit() {
|
||||
|
||||
@@ -746,7 +746,9 @@ private class PpSwitchCase extends PpAst, SwitchCase {
|
||||
override string getPart(int i) {
|
||||
i = 0 and result = "default" and this instanceof DefaultCase
|
||||
or
|
||||
i = 0 and result = "case " and this instanceof ConstCase
|
||||
i = 0 and result = "case " and not this instanceof DefaultCase
|
||||
or
|
||||
i = this.lastConstCaseValueIndex() and result = "default" and this instanceof NullDefaultCase
|
||||
or
|
||||
exists(int j | i = 2 * j and j != 0 and result = ", " and exists(this.(ConstCase).getValue(j)))
|
||||
or
|
||||
@@ -757,8 +759,13 @@ private class PpSwitchCase extends PpAst, SwitchCase {
|
||||
i = 3 + this.lastConstCaseValueIndex() and result = ";" and exists(this.getRuleExpression())
|
||||
}
|
||||
|
||||
private int getCaseDefaultOffset() {
|
||||
if this instanceof NullDefaultCase then result = 1 else result = 0
|
||||
}
|
||||
|
||||
private int lastConstCaseValueIndex() {
|
||||
result = 1 + 2 * max(int j | j = 0 or exists(this.(ConstCase).getValue(j)))
|
||||
result =
|
||||
1 + 2 * (max(int j | j = 0 or exists(this.(ConstCase).getValue(j))) + this.getCaseDefaultOffset())
|
||||
}
|
||||
|
||||
override PpAst getChild(int i) {
|
||||
|
||||
@@ -406,6 +406,9 @@ class SwitchStmt extends Stmt, @switchstmt {
|
||||
/** Gets the `default` case of this switch statement, if any. */
|
||||
DefaultCase getDefaultCase() { result = this.getACase() }
|
||||
|
||||
/** Gets the `default` or `case null, default` case of this switch statement, if any. */
|
||||
SwitchCase getDefaultOrNullDefaultCase() { result = this.getACase() and result.hasDefaultLabel() }
|
||||
|
||||
/** Gets the expression of this `switch` statement. */
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
@@ -487,14 +490,28 @@ class SwitchCase extends Stmt, @case {
|
||||
Stmt getRuleStatementOrExpressionStatement() {
|
||||
result.getParent() = this and result.getIndex() = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this case statement includes the default label, i.e. it is either `default`
|
||||
* or `case null, default`.
|
||||
*/
|
||||
predicate hasDefaultLabel() { this instanceof DefaultCase or this instanceof NullDefaultCase }
|
||||
}
|
||||
|
||||
/** A constant `case` of a switch statement. */
|
||||
/**
|
||||
* A constant `case` of a switch statement.
|
||||
*
|
||||
* Note this excludes `case null, default` even though that includes a null constant. It
|
||||
* does however include plain `case null`.
|
||||
*/
|
||||
class ConstCase extends SwitchCase {
|
||||
ConstCase() {
|
||||
exists(Expr e |
|
||||
e.getParent() = this and e.getIndex() >= 0 and not e instanceof LocalVariableDeclExpr
|
||||
)
|
||||
// For backward compatibility, we don't include `case null, default:` here, on the assumption
|
||||
// this will come as a surprise to CodeQL that predates that statement's validity.
|
||||
and not isNullDefaultCase(this)
|
||||
}
|
||||
|
||||
/** Gets the `case` constant at index 0. */
|
||||
@@ -535,7 +552,11 @@ class PatternCase extends SwitchCase {
|
||||
override string getAPrimaryQlClass() { result = "PatternCase" }
|
||||
}
|
||||
|
||||
/** A `default` case of a `switch` statement */
|
||||
/**
|
||||
* A `default` case of a `switch` statement.
|
||||
*
|
||||
* Note this does not include `case null, default` -- for that, see `NullDefaultCase`.
|
||||
*/
|
||||
class DefaultCase extends SwitchCase {
|
||||
DefaultCase() { not exists(Expr e | e.getParent() = this | e.getIndex() >= 0) }
|
||||
|
||||
@@ -548,6 +569,19 @@ class DefaultCase extends SwitchCase {
|
||||
override string getAPrimaryQlClass() { result = "DefaultCase" }
|
||||
}
|
||||
|
||||
/** A `case null, default` statement of a `switch` statement or expression. */
|
||||
class NullDefaultCase extends SwitchCase {
|
||||
NullDefaultCase() { isNullDefaultCase(this) }
|
||||
|
||||
override string pp() { result = "case null, default" }
|
||||
|
||||
override string toString() { result = "case null, default" }
|
||||
|
||||
override string getHalsteadID() { result = "NullDefaultCase" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NullDefaultCase" }
|
||||
}
|
||||
|
||||
/** A `synchronized` statement. */
|
||||
class SynchronizedStmt extends Stmt, @synchronizedstmt {
|
||||
/** Gets the expression on which this `synchronized` statement synchronizes. */
|
||||
|
||||
@@ -170,10 +170,11 @@ class ConstSwitchStmt extends SwitchStmt {
|
||||
/** Gets the matching case, if it can be deduced. */
|
||||
SwitchCase getMatchingCase() {
|
||||
// Must be a value we can deduce
|
||||
// TODO: handle other known constants (enum constants, String constants)
|
||||
exists(this.getExpr().(ConstantExpr).getIntValue()) and
|
||||
if exists(this.getMatchingConstCase())
|
||||
then result = this.getMatchingConstCase()
|
||||
else result = this.getDefaultCase()
|
||||
else result = this.getDefaultOrNullDefaultCase()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,9 +55,13 @@ predicate implies_v1(Guard g1, boolean b1, Guard g2, boolean b2) {
|
||||
)
|
||||
)
|
||||
or
|
||||
g1.(DefaultCase).getSwitch().getAConstCase() = g2 and b1 = true and b2 = false
|
||||
exists(SwitchCase sc | g1 = sc and sc.hasDefaultLabel() |
|
||||
sc.getSwitch().getAConstCase() = g2 and b1 = true and b2 = false
|
||||
)
|
||||
or
|
||||
g1.(DefaultCase).getSwitchExpr().getAConstCase() = g2 and b1 = true and b2 = false
|
||||
exists(SwitchCase sc | g1 = sc and sc.hasDefaultLabel() |
|
||||
sc.getSwitchExpr().getAConstCase() = g2 and b1 = true and b2 = false
|
||||
)
|
||||
or
|
||||
exists(MethodCall check, int argIndex | check = g1 |
|
||||
conditionCheckArgument(check, argIndex, _) and
|
||||
|
||||
Reference in New Issue
Block a user