Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6566f7b

Browse files
committed
Kotlin: Add types for the different kinds of casts that Kotlin has
We might want to unify some of these in future, but doing that correctly is easier than splitting them up correctly, so I've given each one its own QL class for now. I am not familiar with many of the libraries/queries that use CastExpr. I've briefly looked at them and updated them in a way that looks superficially reasonable, but some of the uses will probably want to be refined later.
1 parent 7cf1289 commit 6566f7b

30 files changed

Lines changed: 155 additions & 96 deletions

File tree

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2394,47 +2394,43 @@ open class KotlinFileExtractor(
23942394
extractExpressionExpr(e.argument, callable, id, 1, enclosingStmt)
23952395
}
23962396
IrTypeOperator.IMPLICIT_CAST -> {
2397-
// TODO: Make this distinguishable from an explicit cast?
2398-
val id = tw.getFreshIdLabel<DbCastexpr>()
2397+
val id = tw.getFreshIdLabel<DbImplicitcastexpr>()
23992398
val locId = tw.getLocation(e)
24002399
val type = useType(e.type)
2401-
tw.writeExprs_castexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
2400+
tw.writeExprs_implicitcastexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
24022401
tw.writeHasLocation(id, locId)
24032402
tw.writeCallableEnclosingExpr(id, callable)
24042403
tw.writeStatementEnclosingExpr(id, enclosingStmt)
24052404
extractTypeAccess(e.typeOperand, callable, id, 0, e, enclosingStmt)
24062405
extractExpressionExpr(e.argument, callable, id, 1, enclosingStmt)
24072406
}
24082407
IrTypeOperator.IMPLICIT_NOTNULL -> {
2409-
// TODO: Make this distinguishable from an explicit cast?
2410-
val id = tw.getFreshIdLabel<DbCastexpr>()
2408+
val id = tw.getFreshIdLabel<DbImplicitnotnullexpr>()
24112409
val locId = tw.getLocation(e)
24122410
val type = useType(e.type)
2413-
tw.writeExprs_castexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
2411+
tw.writeExprs_implicitnotnullexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
24142412
tw.writeHasLocation(id, locId)
24152413
tw.writeCallableEnclosingExpr(id, callable)
24162414
tw.writeStatementEnclosingExpr(id, enclosingStmt)
24172415
extractTypeAccess(e.typeOperand, callable, id, 0, e, enclosingStmt)
24182416
extractExpressionExpr(e.argument, callable, id, 1, enclosingStmt)
24192417
}
24202418
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
2421-
// TODO: Make this distinguishable from an explicit cast?
2422-
val id = tw.getFreshIdLabel<DbCastexpr>()
2419+
val id = tw.getFreshIdLabel<DbImplicitcoerciontounitexpr>()
24232420
val locId = tw.getLocation(e)
24242421
val type = useType(e.type)
2425-
tw.writeExprs_castexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
2422+
tw.writeExprs_implicitcoerciontounitexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
24262423
tw.writeHasLocation(id, locId)
24272424
tw.writeCallableEnclosingExpr(id, callable)
24282425
tw.writeStatementEnclosingExpr(id, enclosingStmt)
24292426
extractTypeAccess(e.typeOperand, callable, id, 0, e, enclosingStmt)
24302427
extractExpressionExpr(e.argument, callable, id, 1, enclosingStmt)
24312428
}
24322429
IrTypeOperator.SAFE_CAST -> {
2433-
// TODO: Distinguish this (e as? T) from CAST
2434-
val id = tw.getFreshIdLabel<DbCastexpr>()
2430+
val id = tw.getFreshIdLabel<DbSafecastexpr>()
24352431
val locId = tw.getLocation(e)
24362432
val type = useType(e.type)
2437-
tw.writeExprs_castexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
2433+
tw.writeExprs_safecastexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
24382434
tw.writeHasLocation(id, locId)
24392435
tw.writeCallableEnclosingExpr(id, callable)
24402436
tw.writeStatementEnclosingExpr(id, enclosingStmt)

java/ql/lib/config/semmlecode.dbscheme

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -695,11 +695,14 @@ case @expr.kind of
695695
| 75 = @whenexpr
696696
| 76 = @getclassexpr
697697
| 77 = @safecastexpr
698-
| 78 = @notinstanceofexpr
699-
| 79 = @stmtexpr
700-
| 80 = @stringtemplateexpr
701-
| 81 = @varargexpr
702-
| 82 = @notnullexpr
698+
| 78 = @implicitcastexpr
699+
| 79 = @implicitnotnullexpr
700+
| 80 = @implicitcoerciontounitexpr
701+
| 81 = @notinstanceofexpr
702+
| 82 = @stmtexpr
703+
| 83 = @stringtemplateexpr
704+
| 84 = @varargexpr
705+
| 85 = @notnullexpr
703706
;
704707

705708
/** Holds if this `when` expression was written as an `if` expression. */

java/ql/lib/semmle/code/java/ControlFlowGraph.qll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -456,9 +456,7 @@ private module ControlFlowGraphImpl {
456456
or
457457
this instanceof UnaryExpr and not this instanceof LogNotExpr
458458
or
459-
this instanceof CastExpr
460-
or
461-
this instanceof SafeCastExpr
459+
this instanceof CastingExpr
462460
or
463461
this instanceof InstanceOfExpr and not this.(InstanceOfExpr).isPattern()
464462
or
@@ -544,9 +542,7 @@ private module ControlFlowGraphImpl {
544542
or
545543
index = 0 and result = this.(UnaryExpr).getExpr()
546544
or
547-
index = 0 and result = this.(CastExpr).getExpr()
548-
or
549-
index = 0 and result = this.(SafeCastExpr).getExpr()
545+
index = 0 and result = this.(CastingExpr).getExpr()
550546
or
551547
index = 0 and result = this.(InstanceOfExpr).getExpr()
552548
or

java/ql/lib/semmle/code/java/Conversions.qll

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -111,28 +111,16 @@ class StringConversionContext extends ConversionSite {
111111
override string kind() { result = "string context" }
112112
}
113113

114-
class CastConversionContext extends ConversionSite {
115-
CastExpr c;
114+
class CastingConversionContext extends ConversionSite {
115+
CastingExpr c;
116116

117-
CastConversionContext() { this = c.getExpr() }
117+
CastingConversionContext() { this = c.getExpr() }
118118

119119
override Type getConversionTarget() { result = c.getType() }
120120

121121
override predicate isImplicit() { none() }
122122

123-
override string kind() { result = "cast context" }
124-
}
125-
126-
class SafeCastConversionContext extends ConversionSite {
127-
SafeCastExpr c;
128-
129-
SafeCastConversionContext() { this = c.getExpr() }
130-
131-
override Type getConversionTarget() { result = c.getType() }
132-
133-
override predicate isImplicit() { none() }
134-
135-
override string kind() { result = "safe cast context" }
123+
override string kind() { result = "casting context" }
136124
}
137125

138126
/**

java/ql/lib/semmle/code/java/Expr.qll

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class CompileTimeConstantExpr extends Expr {
127127
this instanceof Literal
128128
or
129129
// Casts to primitive types and casts to type `String`.
130-
this.(CastExpr).getExpr().isCompileTimeConstant()
130+
this.(CastingExpr).getExpr().isCompileTimeConstant()
131131
or
132132
// The unary operators `+`, `-`, `~`, and `!` (but not `++` or `--`).
133133
this.(PlusExpr).getExpr().isCompileTimeConstant()
@@ -311,7 +311,7 @@ class CompileTimeConstantExpr extends Expr {
311311
or
312312
result = this.(CharacterLiteral).getCodePointValue()
313313
or
314-
exists(CastExpr cast, int val |
314+
exists(CastingExpr cast, int val |
315315
cast = this and val = cast.getExpr().(CompileTimeConstantExpr).getIntValue()
316316
|
317317
if cast.getType().hasName("byte")
@@ -1138,35 +1138,62 @@ class LogNotExpr extends UnaryExpr, @lognotexpr {
11381138
override string getAPrimaryQlClass() { result = "LogNotExpr" }
11391139
}
11401140

1141-
/** A cast expression. */
1142-
class CastExpr extends Expr, @castexpr {
1143-
/** Gets the target type of this cast expression. */
1141+
class CastingExpr extends Expr {
1142+
CastingExpr() {
1143+
this instanceof @castexpr or
1144+
this instanceof @safecastexpr or
1145+
this instanceof @implicitcastexpr or
1146+
this instanceof @implicitnotnullexpr or
1147+
this instanceof @implicitcoerciontounitexpr
1148+
}
1149+
1150+
/** Gets the target type of this casting expression. */
11441151
Expr getTypeExpr() { result.isNthChildOf(this, 0) }
11451152

1146-
/** Gets the expression to which the cast operator is applied. */
1153+
/** Gets the expression to which the casting operator is applied. */
11471154
Expr getExpr() { result.isNthChildOf(this, 1) }
1155+
}
11481156

1157+
/** A cast expression. */
1158+
class CastExpr extends CastingExpr, @castexpr {
11491159
/** Gets a printable representation of this expression. */
11501160
override string toString() { result = "(...)..." }
11511161

11521162
override string getAPrimaryQlClass() { result = "CastExpr" }
11531163
}
11541164

1155-
// TODO: Would this be better as a predicate on CastExpr?
11561165
/** A safe cast expression. */
1157-
class SafeCastExpr extends Expr, @safecastexpr {
1158-
/** Gets the target type of this cast expression. */
1159-
Expr getTypeExpr() { result.isNthChildOf(this, 0) }
1160-
1161-
/** Gets the expression to which the cast operator is applied. */
1162-
Expr getExpr() { result.isNthChildOf(this, 1) }
1163-
1166+
class SafeCastExpr extends CastingExpr, @safecastexpr {
11641167
/** Gets a printable representation of this expression. */
11651168
override string toString() { result = "... as? ..." }
11661169

11671170
override string getAPrimaryQlClass() { result = "SafeCastExpr" }
11681171
}
11691172

1173+
/** An implicit cast expression. */
1174+
class ImplicitCastExpr extends CastingExpr, @implicitcastexpr {
1175+
/** Gets a printable representation of this expression. */
1176+
override string toString() { result = "<implicit cast>" }
1177+
1178+
override string getAPrimaryQlClass() { result = "ImplicitCastExpr" }
1179+
}
1180+
1181+
/** An implicit cast-to-non-null expression. */
1182+
class ImplicitNotNullExpr extends CastingExpr, @implicitnotnullexpr {
1183+
/** Gets a printable representation of this expression. */
1184+
override string toString() { result = "<implicit not null>" }
1185+
1186+
override string getAPrimaryQlClass() { result = "ImplicitNotNullExpr" }
1187+
}
1188+
1189+
/** An implicit coercion-to-unit expression. */
1190+
class ImplicitCoercionToUnitExpr extends CastingExpr, @implicitcoerciontounitexpr {
1191+
/** Gets a printable representation of this expression. */
1192+
override string toString() { result = "<implicit coercion to unit>" }
1193+
1194+
override string getAPrimaryQlClass() { result = "ImplicitCoercionToUnitExpr" }
1195+
}
1196+
11701197
/** A class instance creation expression. */
11711198
class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr {
11721199
/** Gets the number of arguments provided to the constructor of the class instance creation expression. */

java/ql/lib/semmle/code/java/PrettyPrintAst.qll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,36 @@ private class PpCastExpr extends PpAst, CastExpr {
272272
}
273273
}
274274

275+
private class PpSafeCastExpr extends PpAst, SafeCastExpr {
276+
override string getPart(int i) {
277+
i = 1 and result = "as?"
278+
}
279+
280+
override PpAst getChild(int i) {
281+
i = 0 and result = this.getExpr()
282+
or
283+
i = 2 and result = this.getTypeExpr()
284+
}
285+
}
286+
287+
private class PpImplicitCastExpr extends PpAst, ImplicitCastExpr {
288+
override PpAst getChild(int i) {
289+
i = 0 and result = this.getExpr()
290+
}
291+
}
292+
293+
private class PpImplicitNotNullExpr extends PpAst, ImplicitNotNullExpr {
294+
override PpAst getChild(int i) {
295+
i = 0 and result = this.getExpr()
296+
}
297+
}
298+
299+
private class PpImplicitCoercionToUnitExpr extends PpAst, ImplicitCoercionToUnitExpr {
300+
override PpAst getChild(int i) {
301+
i = 0 and result = this.getExpr()
302+
}
303+
}
304+
275305
private class PpCall extends PpAst, Call {
276306
override string getPart(int i) {
277307
i = 1 and exists(this.getQualifier()) and result = "."

java/ql/lib/semmle/code/java/dataflow/NullGuards.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ private import IntegerGuards
1212
/** Gets an expression that is always `null`. */
1313
Expr alwaysNullExpr() {
1414
result instanceof NullLiteral or
15-
result.(CastExpr).getExpr() = alwaysNullExpr()
15+
result.(CastingExpr).getExpr() = alwaysNullExpr()
1616
}
1717

1818
/** Gets an equality test between an expression `e` and an enum constant `c`. */
@@ -62,6 +62,12 @@ Expr clearlyNotNullExpr(Expr reason) {
6262
or
6363
result.(CastExpr).getExpr() = clearlyNotNullExpr(reason)
6464
or
65+
result.(ImplicitCastExpr).getExpr() = clearlyNotNullExpr(reason)
66+
or
67+
result instanceof ImplicitNotNullExpr
68+
or
69+
result instanceof ImplicitCoercionToUnitExpr
70+
or
6571
result.(AssignExpr).getSource() = clearlyNotNullExpr(reason)
6672
or
6773
exists(ConditionalExpr c, Expr r1, Expr r2 |

java/ql/lib/semmle/code/java/dataflow/Nullness.qll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ Expr nullExpr() {
4747
result instanceof NullLiteral or
4848
result.(ChooseExpr).getAResultExpr() = nullExpr() or
4949
result.(AssignExpr).getSource() = nullExpr() or
50-
result.(CastExpr).getExpr() = nullExpr()
50+
result.(CastExpr).getExpr() = nullExpr() or
51+
result.(ImplicitCastExpr).getExpr() = nullExpr() or
52+
result instanceof SafeCastExpr
5153
}
5254

5355
/** An expression of a boxed type that is implicitly unboxed. */
@@ -112,7 +114,8 @@ predicate dereference(Expr e) {
112114
or
113115
exists(ArrayAccess aa | aa.getArray() = e)
114116
or
115-
exists(CastExpr cast |
117+
exists(CastingExpr cast |
118+
(cast instanceof CastExpr or cast instanceof ImplicitCastExpr) and
116119
cast.getExpr() = e and
117120
e.getType() instanceof BoxedType and
118121
cast.getType() instanceof PrimitiveType

java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,13 @@ private predicate safeCast(Type fromtyp, Type totyp) {
360360
/**
361361
* A cast that can be ignored for the purpose of range analysis.
362362
*/
363-
private class RangeAnalysisSafeCastExpr extends CastExpr {
364-
RangeAnalysisSafeCastExpr() { safeCast(getExpr().getType(), getType()) }
363+
private class RangeAnalysisSafeCastingExpr extends CastingExpr {
364+
RangeAnalysisSafeCastingExpr() {
365+
safeCast(getExpr().getType(), getType()) or
366+
this instanceof ImplicitCastExpr or
367+
this instanceof ImplicitNotNullExpr or
368+
this instanceof ImplicitCoercionToUnitExpr
369+
}
365370
}
366371

367372
/**
@@ -380,9 +385,9 @@ private predicate typeBound(Type typ, int lowerbound, int upperbound) {
380385
/**
381386
* A cast to a small integral type that may overflow or underflow.
382387
*/
383-
private class NarrowingCastExpr extends CastExpr {
384-
NarrowingCastExpr() {
385-
not this instanceof RangeAnalysisSafeCastExpr and
388+
private class NarrowingCastingExpr extends CastingExpr {
389+
NarrowingCastingExpr() {
390+
not this instanceof RangeAnalysisSafeCastingExpr and
386391
typeBound(getType(), _, _)
387392
}
388393

@@ -412,7 +417,7 @@ private predicate boundFlowStep(Expr e2, Expr e1, int delta, boolean upper) {
412417
valueFlowStep(e2, e1, delta) and
413418
(upper = true or upper = false)
414419
or
415-
e2.(RangeAnalysisSafeCastExpr).getExpr() = e1 and
420+
e2.(RangeAnalysisSafeCastingExpr).getExpr() = e1 and
416421
delta = 0 and
417422
(upper = true or upper = false)
418423
or
@@ -796,7 +801,7 @@ private predicate baseBound(Expr e, int b, boolean upper) {
796801
* For `upper = true` this means that the cast will not overflow and for
797802
* `upper = false` this means that the cast will not underflow.
798803
*/
799-
private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
804+
private predicate safeNarrowingCast(NarrowingCastingExpr cast, boolean upper) {
800805
exists(int bound | bounded(cast.getExpr(), any(ZeroBound zb), bound, upper, _, _, _) |
801806
upper = true and bound <= cast.getUpperBound()
802807
or
@@ -806,7 +811,7 @@ private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
806811

807812
pragma[noinline]
808813
private predicate boundedCastExpr(
809-
NarrowingCastExpr cast, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
814+
NarrowingCastingExpr cast, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
810815
Reason reason
811816
) {
812817
bounded(cast.getExpr(), b, delta, upper, fromBackEdge, origdelta, reason)
@@ -870,7 +875,7 @@ private predicate bounded(
870875
delta = d / factor
871876
)
872877
or
873-
exists(NarrowingCastExpr cast |
878+
exists(NarrowingCastingExpr cast |
874879
cast = e and
875880
safeNarrowingCast(cast, upper.booleanNot()) and
876881
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)

java/ql/lib/semmle/code/java/dataflow/SSA.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,8 +1114,11 @@ class SsaPhiNode extends SsaVariable, TSsaPhiNode {
11141114
}
11151115
}
11161116

1117-
private class RefTypeCastExpr extends CastExpr {
1118-
RefTypeCastExpr() { this.getType() instanceof RefType }
1117+
private class RefTypeCastingExpr extends CastingExpr {
1118+
RefTypeCastingExpr() {
1119+
this.getType() instanceof RefType and
1120+
not this instanceof SafeCastExpr
1121+
}
11191122
}
11201123

11211124
/**
@@ -1130,5 +1133,5 @@ Expr sameValue(SsaVariable v, VarAccess va) {
11301133
or
11311134
result.(AssignExpr).getSource() = sameValue(v, va)
11321135
or
1133-
result.(RefTypeCastExpr).getExpr() = sameValue(v, va)
1136+
result.(RefTypeCastingExpr).getExpr() = sameValue(v, va)
11341137
}

0 commit comments

Comments
 (0)