mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Extract not-null expression
This commit is contained in:
@@ -544,37 +544,63 @@ open class KotlinFileExtractor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun binop(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>) {
|
private fun unaryOp(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>) {
|
||||||
val locId = tw.getLocation(c)
|
val locId = tw.getLocation(c)
|
||||||
tw.writeHasLocation(id, locId)
|
tw.writeHasLocation(id, locId)
|
||||||
tw.writeCallableEnclosingExpr(id, callable)
|
tw.writeCallableEnclosingExpr(id, callable)
|
||||||
|
|
||||||
val dr = c.dispatchReceiver
|
val dr = c.dispatchReceiver
|
||||||
if(dr != null) {
|
if (dr != null) {
|
||||||
logger.warnElement(Severity.ErrorSevere, "Unexpected dispatch receiver found", c)
|
logger.warnElement(Severity.ErrorSevere, "Unexpected dispatch receiver found", c)
|
||||||
}
|
}
|
||||||
if(c.valueArgumentsCount < 1) {
|
|
||||||
|
if (c.valueArgumentsCount < 1) {
|
||||||
logger.warnElement(Severity.ErrorSevere, "No arguments found", c)
|
logger.warnElement(Severity.ErrorSevere, "No arguments found", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
extractArgument(id, c, callable, 0, "Operand null")
|
||||||
|
|
||||||
|
if (c.valueArgumentsCount > 1) {
|
||||||
|
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun binOp(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>) {
|
||||||
|
val locId = tw.getLocation(c)
|
||||||
|
tw.writeHasLocation(id, locId)
|
||||||
|
tw.writeCallableEnclosingExpr(id, callable)
|
||||||
|
|
||||||
|
val dr = c.dispatchReceiver
|
||||||
|
if (dr != null) {
|
||||||
|
logger.warnElement(Severity.ErrorSevere, "Unexpected dispatch receiver found", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.valueArgumentsCount < 1) {
|
||||||
|
logger.warnElement(Severity.ErrorSevere, "No arguments found", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
extractArgument(id, c, callable, 0, "LHS null")
|
||||||
|
|
||||||
|
if (c.valueArgumentsCount < 2) {
|
||||||
|
logger.warnElement(Severity.ErrorSevere, "No RHS found", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
extractArgument(id, c, callable, 1, "RHS null")
|
||||||
|
|
||||||
|
if (c.valueArgumentsCount > 2) {
|
||||||
|
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractArgument(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>, idx: Int, msg: String) {
|
||||||
|
val op = c.getValueArgument(idx)
|
||||||
|
if (op == null) {
|
||||||
|
logger.warnElement(Severity.ErrorSevere, msg, c)
|
||||||
} else {
|
} else {
|
||||||
val lhs = c.getValueArgument(0)
|
extractExpressionExpr(op, callable, id, idx)
|
||||||
if(lhs == null) {
|
|
||||||
logger.warnElement(Severity.ErrorSevere, "LHS null", c)
|
|
||||||
} else {
|
|
||||||
extractExpressionExpr(lhs, callable, id, 0)
|
|
||||||
}
|
|
||||||
if(c.valueArgumentsCount < 2) {
|
|
||||||
logger.warnElement(Severity.ErrorSevere, "No RHS found", c)
|
|
||||||
} else {
|
|
||||||
val rhs = c.getValueArgument(1)
|
|
||||||
if(rhs == null) {
|
|
||||||
logger.warnElement(Severity.ErrorSevere, "RHS null", c)
|
|
||||||
} else {
|
|
||||||
extractExpressionExpr(rhs, callable, id, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(c.valueArgumentsCount > 2) {
|
|
||||||
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,20 +707,20 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbNeexpr>()
|
val id = tw.getFreshIdLabel<DbNeexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, dr, callable)
|
binOp(id, dr, callable)
|
||||||
}
|
}
|
||||||
c.origin == IrStatementOrigin.EXCLEQEQ && isFunction("kotlin", "Boolean", "not") && c.valueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCall(dr, "EQEQEQ") -> {
|
c.origin == IrStatementOrigin.EXCLEQEQ && isFunction("kotlin", "Boolean", "not") && c.valueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCall(dr, "EQEQEQ") -> {
|
||||||
val id = tw.getFreshIdLabel<DbNeexpr>()
|
val id = tw.getFreshIdLabel<DbNeexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, dr, callable)
|
binOp(id, dr, callable)
|
||||||
}
|
}
|
||||||
c.origin == IrStatementOrigin.EXCLEQ && isFunction("kotlin", "Boolean", "not") && c.valueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCall(dr, "ieee754equals") -> {
|
c.origin == IrStatementOrigin.EXCLEQ && isFunction("kotlin", "Boolean", "not") && c.valueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCall(dr, "ieee754equals") -> {
|
||||||
val id = tw.getFreshIdLabel<DbNeexpr>()
|
val id = tw.getFreshIdLabel<DbNeexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
// TODO: Is this consistent with Java?
|
// TODO: Is this consistent with Java?
|
||||||
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, dr, callable)
|
binOp(id, dr, callable)
|
||||||
}
|
}
|
||||||
// We need to handle all the builtin operators defines in BuiltInOperatorNames in
|
// We need to handle all the builtin operators defines in BuiltInOperatorNames in
|
||||||
// compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt
|
// compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt
|
||||||
@@ -706,7 +732,7 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbLtexpr>()
|
val id = tw.getFreshIdLabel<DbLtexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_ltexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_ltexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, c, callable)
|
binOp(id, c, callable)
|
||||||
}
|
}
|
||||||
isBuiltinCall(c, "lessOrEqual") -> {
|
isBuiltinCall(c, "lessOrEqual") -> {
|
||||||
if(c.origin != IrStatementOrigin.LTEQ) {
|
if(c.origin != IrStatementOrigin.LTEQ) {
|
||||||
@@ -715,7 +741,7 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbLeexpr>()
|
val id = tw.getFreshIdLabel<DbLeexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_leexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_leexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, c, callable)
|
binOp(id, c, callable)
|
||||||
}
|
}
|
||||||
isBuiltinCall(c, "greater") -> {
|
isBuiltinCall(c, "greater") -> {
|
||||||
if(c.origin != IrStatementOrigin.GT) {
|
if(c.origin != IrStatementOrigin.GT) {
|
||||||
@@ -724,7 +750,7 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbGtexpr>()
|
val id = tw.getFreshIdLabel<DbGtexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_gtexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_gtexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, c, callable)
|
binOp(id, c, callable)
|
||||||
}
|
}
|
||||||
isBuiltinCall(c, "greaterOrEqual") -> {
|
isBuiltinCall(c, "greaterOrEqual") -> {
|
||||||
if(c.origin != IrStatementOrigin.GTEQ) {
|
if(c.origin != IrStatementOrigin.GTEQ) {
|
||||||
@@ -733,7 +759,7 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbGeexpr>()
|
val id = tw.getFreshIdLabel<DbGeexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_geexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_geexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, c, callable)
|
binOp(id, c, callable)
|
||||||
}
|
}
|
||||||
isBuiltinCall(c, "EQEQ") -> {
|
isBuiltinCall(c, "EQEQ") -> {
|
||||||
if(c.origin != IrStatementOrigin.EQEQ) {
|
if(c.origin != IrStatementOrigin.EQEQ) {
|
||||||
@@ -743,7 +769,7 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbEqexpr>()
|
val id = tw.getFreshIdLabel<DbEqexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, c, callable)
|
binOp(id, c, callable)
|
||||||
}
|
}
|
||||||
isBuiltinCall(c, "EQEQEQ") -> {
|
isBuiltinCall(c, "EQEQEQ") -> {
|
||||||
if(c.origin != IrStatementOrigin.EQEQEQ) {
|
if(c.origin != IrStatementOrigin.EQEQEQ) {
|
||||||
@@ -752,7 +778,7 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbEqexpr>()
|
val id = tw.getFreshIdLabel<DbEqexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, c, callable)
|
binOp(id, c, callable)
|
||||||
}
|
}
|
||||||
isBuiltinCall(c, "ieee754equals") -> {
|
isBuiltinCall(c, "ieee754equals") -> {
|
||||||
if(c.origin != IrStatementOrigin.EQEQ) {
|
if(c.origin != IrStatementOrigin.EQEQ) {
|
||||||
@@ -762,7 +788,17 @@ open class KotlinFileExtractor(
|
|||||||
val id = tw.getFreshIdLabel<DbEqexpr>()
|
val id = tw.getFreshIdLabel<DbEqexpr>()
|
||||||
val type = useType(c.type)
|
val type = useType(c.type)
|
||||||
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
binop(id, c, callable)
|
binOp(id, c, callable)
|
||||||
|
}
|
||||||
|
isBuiltinCall(c, "CHECK_NOT_NULL") -> {
|
||||||
|
if(c.origin != IrStatementOrigin.EXCLEXCL) {
|
||||||
|
logger.warnElement(Severity.ErrorSevere, "Unexpected origin for CHECK_NOT_NULL: ${c.origin}", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
val id = tw.getFreshIdLabel<DbNotnullexpr>()
|
||||||
|
val type = useType(c.type)
|
||||||
|
tw.writeExprs_notnullexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||||
|
unaryOp(id, c, callable)
|
||||||
}
|
}
|
||||||
isBuiltinCall(c, "THROW_CCE") -> {
|
isBuiltinCall(c, "THROW_CCE") -> {
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
@@ -695,6 +695,7 @@ case @expr.kind of
|
|||||||
| 79 = @stmtexpr
|
| 79 = @stmtexpr
|
||||||
| 80 = @stringtemplateexpr
|
| 80 = @stringtemplateexpr
|
||||||
| 81 = @varargexpr
|
| 81 = @varargexpr
|
||||||
|
| 82 = @notnullexpr
|
||||||
;
|
;
|
||||||
|
|
||||||
/** Holds if this `when` expression was written as an `if` expression. */
|
/** Holds if this `when` expression was written as an `if` expression. */
|
||||||
@@ -771,7 +772,8 @@ when_branch_else(unique int id: @whenbranch ref);
|
|||||||
| @minusexpr
|
| @minusexpr
|
||||||
| @plusexpr
|
| @plusexpr
|
||||||
| @bitnotexpr
|
| @bitnotexpr
|
||||||
| @lognotexpr;
|
| @lognotexpr
|
||||||
|
| @notnullexpr;
|
||||||
|
|
||||||
@caller = @classinstancexpr
|
@caller = @classinstancexpr
|
||||||
| @methodaccess
|
| @methodaccess
|
||||||
|
|||||||
@@ -1463,9 +1463,7 @@ class InstanceOfExpr extends Expr, @instanceofexpr {
|
|||||||
/** An `instanceof` expression. */
|
/** An `instanceof` expression. */
|
||||||
class NotInstanceOfExpr extends Expr, @notinstanceofexpr {
|
class NotInstanceOfExpr extends Expr, @notinstanceofexpr {
|
||||||
/** Gets the expression on the left-hand side of the `!is` operator. */
|
/** Gets the expression on the left-hand side of the `!is` operator. */
|
||||||
Expr getExpr() {
|
Expr getExpr() { result.isNthChildOf(this, 0) }
|
||||||
result.isNthChildOf(this, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the access to the type on the right-hand side of the `!is` operator. */
|
/** Gets the access to the type on the right-hand side of the `!is` operator. */
|
||||||
Expr getTypeName() { result.isNthChildOf(this, 1) }
|
Expr getTypeName() { result.isNthChildOf(this, 1) }
|
||||||
@@ -2195,19 +2193,13 @@ class WhenBranch extends Top, @whenbranch {
|
|||||||
Expr getCondition() { result.isNthChildOf(this, 0) }
|
Expr getCondition() { result.isNthChildOf(this, 0) }
|
||||||
|
|
||||||
/** Gets the result of this branch. */
|
/** Gets the result of this branch. */
|
||||||
Stmt getRhs() {
|
Stmt getRhs() { result.isNthChildOf(this, 1) }
|
||||||
result.isNthChildOf(this, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a result expression of this `when` branch. */
|
/** Gets a result expression of this `when` branch. */
|
||||||
Expr getAResult() {
|
Expr getAResult() { result = getAResult(this.getRhs()) }
|
||||||
result = getAResult(this.getRhs())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this is an `else` branch. */
|
/** Holds if this is an `else` branch. */
|
||||||
predicate isElseBranch() {
|
predicate isElseBranch() { when_branch_else(this) }
|
||||||
when_branch_else(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override string toString() { result = "... -> ..." }
|
override string toString() { result = "... -> ..." }
|
||||||
|
|
||||||
@@ -2290,3 +2282,10 @@ class VarArgExpr extends Expr, @varargexpr {
|
|||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "VarArgExpr" }
|
override string getAPrimaryQlClass() { result = "VarArgExpr" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A Kotlin not-null expression. For example, `expr!!`. */
|
||||||
|
class NotNullExpr extends UnaryExpr, @notnullexpr {
|
||||||
|
override string toString() { result = "...!!" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "NotNullExpr" }
|
||||||
|
}
|
||||||
|
|||||||
@@ -534,6 +534,9 @@
|
|||||||
| exprs.kt:193:31:193:37 | ... + ... | exprs.kt:192:16:194:9 | <obinit> | AddExpr |
|
| exprs.kt:193:31:193:37 | ... + ... | exprs.kt:192:16:194:9 | <obinit> | AddExpr |
|
||||||
| exprs.kt:193:36:193:37 | a2 | exprs.kt:192:16:194:9 | <obinit> | VarAccess |
|
| exprs.kt:193:36:193:37 | a2 | exprs.kt:192:16:194:9 | <obinit> | VarAccess |
|
||||||
| exprs.kt:193:40:193:49 | toString(...) | exprs.kt:192:16:194:9 | <obinit> | MethodAccess |
|
| exprs.kt:193:40:193:49 | toString(...) | exprs.kt:192:16:194:9 | <obinit> | MethodAccess |
|
||||||
|
| exprs.kt:199:5:199:20 | y | exprs.kt:198:1:200:1 | notNullAssertion | LocalVariableDeclExpr |
|
||||||
|
| exprs.kt:199:18:199:18 | x | exprs.kt:198:1:200:1 | notNullAssertion | VarAccess |
|
||||||
|
| exprs.kt:199:19:199:20 | ...!! | exprs.kt:198:1:200:1 | notNullAssertion | NotNullExpr |
|
||||||
| file://:0:0:0:0 | C | exprs.kt:146:5:146:33 | foo | TypeAccess |
|
| file://:0:0:0:0 | C | exprs.kt:146:5:146:33 | foo | TypeAccess |
|
||||||
| file://:0:0:0:0 | Color | exprs.kt:175:6:179:1 | Color | TypeAccess |
|
| file://:0:0:0:0 | Color | exprs.kt:175:6:179:1 | Color | TypeAccess |
|
||||||
| file://:0:0:0:0 | Direction | exprs.kt:171:6:173:1 | Direction | TypeAccess |
|
| file://:0:0:0:0 | Direction | exprs.kt:171:6:173:1 | Direction | TypeAccess |
|
||||||
|
|||||||
@@ -194,3 +194,7 @@ class Class1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun notNullAssertion(x: Any?) {
|
||||||
|
val y: Any = x!!
|
||||||
|
}
|
||||||
|
|||||||
1
java/ql/test/kotlin/library-tests/exprs/unaryOp.expected
Normal file
1
java/ql/test/kotlin/library-tests/exprs/unaryOp.expected
Normal file
@@ -0,0 +1 @@
|
|||||||
|
| exprs.kt:199:19:199:20 | ...!! | exprs.kt:199:18:199:18 | x |
|
||||||
36
java/ql/test/kotlin/library-tests/exprs/unaryOp.ql
Normal file
36
java/ql/test/kotlin/library-tests/exprs/unaryOp.ql
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import java
|
||||||
|
|
||||||
|
newtype TMaybeElement =
|
||||||
|
TElement(Element e) or
|
||||||
|
TNoElement()
|
||||||
|
|
||||||
|
class MaybeElement extends TMaybeElement {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
abstract Location getLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
class YesMaybeElement extends MaybeElement {
|
||||||
|
Element e;
|
||||||
|
|
||||||
|
YesMaybeElement() { this = TElement(e) }
|
||||||
|
|
||||||
|
override string toString() { result = e.toString() }
|
||||||
|
|
||||||
|
override Location getLocation() { result = e.getLocation() }
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoMaybeElement extends MaybeElement {
|
||||||
|
NoMaybeElement() { this = TNoElement() }
|
||||||
|
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
|
||||||
|
override Location getLocation() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeElement op(UnaryExpr e) {
|
||||||
|
if exists(e.getExpr()) then result = TElement(e.getExpr()) else result = TNoElement()
|
||||||
|
}
|
||||||
|
|
||||||
|
from Expr e
|
||||||
|
select e, op(e)
|
||||||
Reference in New Issue
Block a user