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

Skip to content

Commit 716b87d

Browse files
tamasvajkigfoo
authored andcommitted
Extract not-null expression
1 parent 6603767 commit 716b87d

7 files changed

Lines changed: 126 additions & 45 deletions

File tree

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

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -544,37 +544,63 @@ open class KotlinFileExtractor(
544544
return true
545545
}
546546

547-
fun binop(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>) {
547+
private fun unaryOp(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>) {
548548
val locId = tw.getLocation(c)
549549
tw.writeHasLocation(id, locId)
550550
tw.writeCallableEnclosingExpr(id, callable)
551551

552552
val dr = c.dispatchReceiver
553-
if(dr != null) {
553+
if (dr != null) {
554+
logger.warnElement(Severity.ErrorSevere, "Unexpected dispatch receiver found", c)
555+
}
556+
557+
if (c.valueArgumentsCount < 1) {
558+
logger.warnElement(Severity.ErrorSevere, "No arguments found", c)
559+
return
560+
}
561+
562+
extractArgument(id, c, callable, 0, "Operand null")
563+
564+
if (c.valueArgumentsCount > 1) {
565+
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
566+
}
567+
}
568+
569+
private fun binOp(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>) {
570+
val locId = tw.getLocation(c)
571+
tw.writeHasLocation(id, locId)
572+
tw.writeCallableEnclosingExpr(id, callable)
573+
574+
val dr = c.dispatchReceiver
575+
if (dr != null) {
554576
logger.warnElement(Severity.ErrorSevere, "Unexpected dispatch receiver found", c)
555577
}
556-
if(c.valueArgumentsCount < 1) {
578+
579+
if (c.valueArgumentsCount < 1) {
557580
logger.warnElement(Severity.ErrorSevere, "No arguments found", c)
581+
return
582+
}
583+
584+
extractArgument(id, c, callable, 0, "LHS null")
585+
586+
if (c.valueArgumentsCount < 2) {
587+
logger.warnElement(Severity.ErrorSevere, "No RHS found", c)
588+
return
589+
}
590+
591+
extractArgument(id, c, callable, 1, "RHS null")
592+
593+
if (c.valueArgumentsCount > 2) {
594+
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
595+
}
596+
}
597+
598+
private fun extractArgument(id: Label<out DbExpr>, c: IrCall, callable: Label<out DbCallable>, idx: Int, msg: String) {
599+
val op = c.getValueArgument(idx)
600+
if (op == null) {
601+
logger.warnElement(Severity.ErrorSevere, msg, c)
558602
} else {
559-
val lhs = c.getValueArgument(0)
560-
if(lhs == null) {
561-
logger.warnElement(Severity.ErrorSevere, "LHS null", c)
562-
} else {
563-
extractExpressionExpr(lhs, callable, id, 0)
564-
}
565-
if(c.valueArgumentsCount < 2) {
566-
logger.warnElement(Severity.ErrorSevere, "No RHS found", c)
567-
} else {
568-
val rhs = c.getValueArgument(1)
569-
if(rhs == null) {
570-
logger.warnElement(Severity.ErrorSevere, "RHS null", c)
571-
} else {
572-
extractExpressionExpr(rhs, callable, id, 1)
573-
}
574-
}
575-
if(c.valueArgumentsCount > 2) {
576-
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
577-
}
603+
extractExpressionExpr(op, callable, id, idx)
578604
}
579605
}
580606

@@ -681,20 +707,20 @@ open class KotlinFileExtractor(
681707
val id = tw.getFreshIdLabel<DbNeexpr>()
682708
val type = useType(c.type)
683709
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
684-
binop(id, dr, callable)
710+
binOp(id, dr, callable)
685711
}
686712
c.origin == IrStatementOrigin.EXCLEQEQ && isFunction("kotlin", "Boolean", "not") && c.valueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCall(dr, "EQEQEQ") -> {
687713
val id = tw.getFreshIdLabel<DbNeexpr>()
688714
val type = useType(c.type)
689715
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
690-
binop(id, dr, callable)
716+
binOp(id, dr, callable)
691717
}
692718
c.origin == IrStatementOrigin.EXCLEQ && isFunction("kotlin", "Boolean", "not") && c.valueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCall(dr, "ieee754equals") -> {
693719
val id = tw.getFreshIdLabel<DbNeexpr>()
694720
val type = useType(c.type)
695721
// TODO: Is this consistent with Java?
696722
tw.writeExprs_neexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
697-
binop(id, dr, callable)
723+
binOp(id, dr, callable)
698724
}
699725
// We need to handle all the builtin operators defines in BuiltInOperatorNames in
700726
// compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt
@@ -706,7 +732,7 @@ open class KotlinFileExtractor(
706732
val id = tw.getFreshIdLabel<DbLtexpr>()
707733
val type = useType(c.type)
708734
tw.writeExprs_ltexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
709-
binop(id, c, callable)
735+
binOp(id, c, callable)
710736
}
711737
isBuiltinCall(c, "lessOrEqual") -> {
712738
if(c.origin != IrStatementOrigin.LTEQ) {
@@ -715,7 +741,7 @@ open class KotlinFileExtractor(
715741
val id = tw.getFreshIdLabel<DbLeexpr>()
716742
val type = useType(c.type)
717743
tw.writeExprs_leexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
718-
binop(id, c, callable)
744+
binOp(id, c, callable)
719745
}
720746
isBuiltinCall(c, "greater") -> {
721747
if(c.origin != IrStatementOrigin.GT) {
@@ -724,7 +750,7 @@ open class KotlinFileExtractor(
724750
val id = tw.getFreshIdLabel<DbGtexpr>()
725751
val type = useType(c.type)
726752
tw.writeExprs_gtexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
727-
binop(id, c, callable)
753+
binOp(id, c, callable)
728754
}
729755
isBuiltinCall(c, "greaterOrEqual") -> {
730756
if(c.origin != IrStatementOrigin.GTEQ) {
@@ -733,7 +759,7 @@ open class KotlinFileExtractor(
733759
val id = tw.getFreshIdLabel<DbGeexpr>()
734760
val type = useType(c.type)
735761
tw.writeExprs_geexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
736-
binop(id, c, callable)
762+
binOp(id, c, callable)
737763
}
738764
isBuiltinCall(c, "EQEQ") -> {
739765
if(c.origin != IrStatementOrigin.EQEQ) {
@@ -743,7 +769,7 @@ open class KotlinFileExtractor(
743769
val id = tw.getFreshIdLabel<DbEqexpr>()
744770
val type = useType(c.type)
745771
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
746-
binop(id, c, callable)
772+
binOp(id, c, callable)
747773
}
748774
isBuiltinCall(c, "EQEQEQ") -> {
749775
if(c.origin != IrStatementOrigin.EQEQEQ) {
@@ -752,7 +778,7 @@ open class KotlinFileExtractor(
752778
val id = tw.getFreshIdLabel<DbEqexpr>()
753779
val type = useType(c.type)
754780
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
755-
binop(id, c, callable)
781+
binOp(id, c, callable)
756782
}
757783
isBuiltinCall(c, "ieee754equals") -> {
758784
if(c.origin != IrStatementOrigin.EQEQ) {
@@ -762,7 +788,17 @@ open class KotlinFileExtractor(
762788
val id = tw.getFreshIdLabel<DbEqexpr>()
763789
val type = useType(c.type)
764790
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
765-
binop(id, c, callable)
791+
binOp(id, c, callable)
792+
}
793+
isBuiltinCall(c, "CHECK_NOT_NULL") -> {
794+
if(c.origin != IrStatementOrigin.EXCLEXCL) {
795+
logger.warnElement(Severity.ErrorSevere, "Unexpected origin for CHECK_NOT_NULL: ${c.origin}", c)
796+
}
797+
798+
val id = tw.getFreshIdLabel<DbNotnullexpr>()
799+
val type = useType(c.type)
800+
tw.writeExprs_notnullexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
801+
unaryOp(id, c, callable)
766802
}
767803
isBuiltinCall(c, "THROW_CCE") -> {
768804
// TODO

java/ql/lib/config/semmlecode.dbscheme

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ case @expr.kind of
695695
| 79 = @stmtexpr
696696
| 80 = @stringtemplateexpr
697697
| 81 = @varargexpr
698+
| 82 = @notnullexpr
698699
;
699700

700701
/** Holds if this `when` expression was written as an `if` expression. */
@@ -771,7 +772,8 @@ when_branch_else(unique int id: @whenbranch ref);
771772
| @minusexpr
772773
| @plusexpr
773774
| @bitnotexpr
774-
| @lognotexpr;
775+
| @lognotexpr
776+
| @notnullexpr;
775777

776778
@caller = @classinstancexpr
777779
| @methodaccess

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,9 +1463,7 @@ class InstanceOfExpr extends Expr, @instanceofexpr {
14631463
/** An `instanceof` expression. */
14641464
class NotInstanceOfExpr extends Expr, @notinstanceofexpr {
14651465
/** Gets the expression on the left-hand side of the `!is` operator. */
1466-
Expr getExpr() {
1467-
result.isNthChildOf(this, 0)
1468-
}
1466+
Expr getExpr() { result.isNthChildOf(this, 0) }
14691467

14701468
/** Gets the access to the type on the right-hand side of the `!is` operator. */
14711469
Expr getTypeName() { result.isNthChildOf(this, 1) }
@@ -2195,19 +2193,13 @@ class WhenBranch extends Top, @whenbranch {
21952193
Expr getCondition() { result.isNthChildOf(this, 0) }
21962194

21972195
/** Gets the result of this branch. */
2198-
Stmt getRhs() {
2199-
result.isNthChildOf(this, 1)
2200-
}
2196+
Stmt getRhs() { result.isNthChildOf(this, 1) }
22012197

22022198
/** Gets a result expression of this `when` branch. */
2203-
Expr getAResult() {
2204-
result = getAResult(this.getRhs())
2205-
}
2199+
Expr getAResult() { result = getAResult(this.getRhs()) }
22062200

22072201
/** Holds if this is an `else` branch. */
2208-
predicate isElseBranch() {
2209-
when_branch_else(this)
2210-
}
2202+
predicate isElseBranch() { when_branch_else(this) }
22112203

22122204
override string toString() { result = "... -> ..." }
22132205

@@ -2290,3 +2282,10 @@ class VarArgExpr extends Expr, @varargexpr {
22902282

22912283
override string getAPrimaryQlClass() { result = "VarArgExpr" }
22922284
}
2285+
2286+
/** A Kotlin not-null expression. For example, `expr!!`. */
2287+
class NotNullExpr extends UnaryExpr, @notnullexpr {
2288+
override string toString() { result = "...!!" }
2289+
2290+
override string getAPrimaryQlClass() { result = "NotNullExpr" }
2291+
}

java/ql/test/kotlin/library-tests/exprs/exprs.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,9 @@
534534
| exprs.kt:193:31:193:37 | ... + ... | exprs.kt:192:16:194:9 | <obinit> | AddExpr |
535535
| exprs.kt:193:36:193:37 | a2 | exprs.kt:192:16:194:9 | <obinit> | VarAccess |
536536
| exprs.kt:193:40:193:49 | toString(...) | exprs.kt:192:16:194:9 | <obinit> | MethodAccess |
537+
| exprs.kt:199:5:199:20 | y | exprs.kt:198:1:200:1 | notNullAssertion | LocalVariableDeclExpr |
538+
| exprs.kt:199:18:199:18 | x | exprs.kt:198:1:200:1 | notNullAssertion | VarAccess |
539+
| exprs.kt:199:19:199:20 | ...!! | exprs.kt:198:1:200:1 | notNullAssertion | NotNullExpr |
537540
| file://:0:0:0:0 | C | exprs.kt:146:5:146:33 | foo | TypeAccess |
538541
| file://:0:0:0:0 | Color | exprs.kt:175:6:179:1 | Color | TypeAccess |
539542
| file://:0:0:0:0 | Direction | exprs.kt:171:6:173:1 | Direction | TypeAccess |

java/ql/test/kotlin/library-tests/exprs/exprs.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,7 @@ class Class1 {
194194
}
195195
}
196196
}
197+
198+
fun notNullAssertion(x: Any?) {
199+
val y: Any = x!!
200+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| exprs.kt:199:19:199:20 | ...!! | exprs.kt:199:18:199:18 | x |
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import java
2+
3+
newtype TMaybeElement =
4+
TElement(Element e) or
5+
TNoElement()
6+
7+
class MaybeElement extends TMaybeElement {
8+
abstract string toString();
9+
10+
abstract Location getLocation();
11+
}
12+
13+
class YesMaybeElement extends MaybeElement {
14+
Element e;
15+
16+
YesMaybeElement() { this = TElement(e) }
17+
18+
override string toString() { result = e.toString() }
19+
20+
override Location getLocation() { result = e.getLocation() }
21+
}
22+
23+
class NoMaybeElement extends MaybeElement {
24+
NoMaybeElement() { this = TNoElement() }
25+
26+
override string toString() { result = "<none>" }
27+
28+
override Location getLocation() { none() }
29+
}
30+
31+
MaybeElement op(UnaryExpr e) {
32+
if exists(e.getExpr()) then result = TElement(e.getExpr()) else result = TNoElement()
33+
}
34+
35+
from Expr e
36+
select e, op(e)

0 commit comments

Comments
 (0)