Kotlin: Add support for more type operators

This commit is contained in:
Ian Lynagh
2021-10-28 13:49:42 +01:00
parent d247e4fcff
commit ba7a7535e9
7 changed files with 102 additions and 9 deletions

View File

@@ -667,6 +667,8 @@ case @expr.kind of
| 74 = @errorexpr
| 75 = @whenexpr
| 76 = @getclassexpr
| 77 = @safecastexpr
| 78 = @notinstanceofexpr
;
/** Holds if this `when` expression was written as an `if` expression. */

View File

@@ -448,8 +448,12 @@ private module ControlFlowGraphImpl {
or
this instanceof CastExpr
or
this instanceof SafeCastExpr
or
this instanceof InstanceOfExpr and not this.(InstanceOfExpr).isPattern()
or
this instanceof NotInstanceOfExpr
or
this instanceof LocalVariableDeclExpr and
not this = any(InstanceOfExpr ioe).getLocalVariableDeclExpr()
or
@@ -526,8 +530,12 @@ private module ControlFlowGraphImpl {
or
index = 0 and result = this.(CastExpr).getExpr()
or
index = 0 and result = this.(SafeCastExpr).getExpr()
or
index = 0 and result = this.(InstanceOfExpr).getExpr()
or
index = 0 and result = this.(NotInstanceOfExpr).getExpr()
or
index = 0 and result = this.(LocalVariableDeclExpr).getInit()
or
index = 0 and result = this.(RValue).getQualifier() and not result instanceof TypeAccess
@@ -599,6 +607,8 @@ private module ControlFlowGraphImpl {
or
result = first(n.(InstanceOfExpr).getExpr())
or
result = first(n.(NotInstanceOfExpr).getExpr())
or
result = first(n.(SynchronizedStmt).getExpr())
or
result = n and

View File

@@ -123,6 +123,18 @@ class CastConversionContext extends ConversionSite {
override string kind() { result = "cast context" }
}
class SafeCastConversionContext extends ConversionSite {
SafeCastExpr c;
CastConversionContext() { this = c.getExpr() }
override Type getConversionTarget() { result = c.getType() }
override predicate isImplicit() { none() }
override string kind() { result = "safe cast context" }
}
/**
* A numeric conversion. For example, `a * b` converts `a` and
* `b` to have an appropriate numeric type.

View File

@@ -1152,6 +1152,21 @@ class CastExpr extends Expr, @castexpr {
override string getAPrimaryQlClass() { result = "CastExpr" }
}
// TODO: Would this be better as a predicate on CastExpr?
/** A safe cast expression. */
class SafeCastExpr extends Expr, @safecastexpr {
/** Gets the target type of this cast expression. */
Expr getTypeExpr() { result.isNthChildOf(this, 0) }
/** Gets the expression to which the cast operator is applied. */
Expr getExpr() { result.isNthChildOf(this, 1) }
/** Gets a printable representation of this expression. */
override string toString() { result = "... as? ..." }
override string getAPrimaryQlClass() { result = "SafeCastExpr" }
}
/** A class instance creation expression. */
class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr {
/** Gets the number of arguments provided to the constructor of the class instance creation expression. */
@@ -1442,6 +1457,28 @@ class InstanceOfExpr extends Expr, @instanceofexpr {
override string getAPrimaryQlClass() { result = "InstanceOfExpr" }
}
// TODO: Should this be desugared into instanceof.not()?
// Note expressions/IrTypeOperatorCall.kt says:
// NOT_INSTANCEOF, // TODO drop and replace with `INSTANCEOF<T>(x).not()`?
/** An `instanceof` expression. */
class NotInstanceOfExpr extends Expr, @notinstanceofexpr {
/** Gets the expression on the left-hand side of the `!is` operator. */
Expr getExpr() {
result.isNthChildOf(this, 0)
}
/** Gets the access to the type on the right-hand side of the `!is` operator. */
Expr getTypeName() { result.isNthChildOf(this, 1) }
/** Gets the type this `!is` expression checks for. */
RefType getCheckedType() { result = getTypeName().getType() }
/** Gets a printable representation of this expression. */
override string toString() { result = "... !is ..." }
override string getAPrimaryQlClass() { result = "NotInstanceOfExpr" }
}
/**
* A local variable declaration expression.
*

View File

@@ -360,8 +360,8 @@ private predicate safeCast(Type fromtyp, Type totyp) {
/**
* A cast that can be ignored for the purpose of range analysis.
*/
private class SafeCastExpr extends CastExpr {
SafeCastExpr() { safeCast(getExpr().getType(), getType()) }
private class RangeAnalysisSafeCastExpr extends CastExpr {
RangeAnalysisSafeCastExpr() { safeCast(getExpr().getType(), getType()) }
}
/**
@@ -382,7 +382,7 @@ private predicate typeBound(Type typ, int lowerbound, int upperbound) {
*/
private class NarrowingCastExpr extends CastExpr {
NarrowingCastExpr() {
not this instanceof SafeCastExpr and
not this instanceof RangeAnalysisSafeCastExpr and
typeBound(getType(), _, _)
}
@@ -412,7 +412,7 @@ private predicate boundFlowStep(Expr e2, Expr e1, int delta, boolean upper) {
valueFlowStep(e2, e1, delta) and
(upper = true or upper = false)
or
e2.(SafeCastExpr).getExpr() = e1 and
e2.(RangeAnalysisSafeCastExpr).getExpr() = e1 and
delta = 0 and
(upper = true or upper = false)
or

View File

@@ -54,8 +54,15 @@
| exprs.kt:40:5:40:22 | b6 | LocalVariableDeclExpr |
| exprs.kt:40:14:40:15 | i1 | VarAccess |
| exprs.kt:40:14:40:22 | ...instanceof... | InstanceOfExpr |
| exprs.kt:40:14:40:22 | int | TypeAccess |
| exprs.kt:41:5:41:23 | b7 | LocalVariableDeclExpr |
| exprs.kt:41:14:41:15 | i1 | VarAccess |
| exprs.kt:41:14:41:23 | ... !is ... | NotInstanceOfExpr |
| exprs.kt:41:14:41:23 | int | TypeAccess |
| exprs.kt:42:5:42:26 | b8 | LocalVariableDeclExpr |
| exprs.kt:42:14:42:15 | b7 | VarAccess |
| exprs.kt:42:14:42:26 | (...)... | CastExpr |
| exprs.kt:42:14:42:26 | boolean | TypeAccess |
| exprs.kt:43:5:43:35 | str1 | LocalVariableDeclExpr |
| exprs.kt:43:25:43:34 | string lit | StringLiteral |
| exprs.kt:44:5:44:36 | str2 | LocalVariableDeclExpr |
@@ -74,4 +81,3 @@
| exprs.kt:53:9:53:18 | n | VarAccess |
| exprs.kt:54:27:54:31 | new C(...) | ClassInstanceExpr |
| exprs.kt:54:29:54:30 | 42 | IntegerLiteral |
| file://:0:0:0:0 | int | TypeAccess |