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

Skip to content

Commit 744f3db

Browse files
committed
Kotlin: Handle binops correctly
1 parent d63ef23 commit 744f3db

5 files changed

Lines changed: 193 additions & 85 deletions

File tree

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

Lines changed: 134 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ fun doFile(invocationTrapFile: String,
172172
}
173173

174174
fun <T> fakeLabel(): Label<T> {
175-
if (true) {
175+
if (false) {
176176
println("Fake label")
177177
} else {
178178
val sw = StringWriter()
@@ -1414,53 +1414,144 @@ open class KotlinFileExtractor(
14141414
}
14151415

14161416
fun extractCall(c: IrCall, callable: Label<out DbCallable>, parent: Label<out DbExprparent>, idx: Int) {
1417-
val exprId: Label<out DbExpr> = when (c.origin) {
1418-
PLUS -> {
1417+
fun isFunction(pkgName: String, className: String?, fName: String): Boolean {
1418+
val verbose = false
1419+
fun verboseln(s: String) { if(verbose) println(s) }
1420+
verboseln("Attempting match for $pkgName $className $fName")
1421+
val target = c.symbol.owner
1422+
if (target.name.asString() != fName) {
1423+
verboseln("No match as function name is ${target.name.asString()} not $fName")
1424+
return false
1425+
}
1426+
val extensionReceiverParameter = target.extensionReceiverParameter
1427+
val targetClass = if (extensionReceiverParameter == null) target.parent
1428+
else (extensionReceiverParameter.type as? IrSimpleType)?.classifier?.owner
1429+
val targetPkg =
1430+
if (className != null) {
1431+
if (targetClass !is IrClass) {
1432+
verboseln("No match as didn't find target class")
1433+
return false
1434+
}
1435+
if (targetClass.name.asString() != className) {
1436+
verboseln("No match as class name is ${targetClass.name.asString()} not $className")
1437+
return false
1438+
}
1439+
targetClass.parent
1440+
} else {
1441+
targetClass
1442+
}
1443+
if (targetPkg !is IrPackageFragment) {
1444+
verboseln("No match as didn't find target package")
1445+
return false
1446+
}
1447+
if (targetPkg.fqName.asString() != pkgName) {
1448+
verboseln("No match as class name is ${targetPkg.fqName.asString()} not $pkgName")
1449+
return false
1450+
}
1451+
verboseln("Match")
1452+
return true
1453+
}
1454+
1455+
fun binopDisp(id: Label<out DbExpr>) {
1456+
val locId = tw.getLocation(c)
1457+
tw.writeHasLocation(id, locId)
1458+
tw.writeCallableEnclosingExpr(id, callable)
1459+
1460+
val dr = c.dispatchReceiver
1461+
if(dr == null) {
1462+
logger.warnElement(Severity.ErrorSevere, "Dispatch receiver not found", c)
1463+
} else {
1464+
extractExpressionExpr(dr, callable, id, 0)
1465+
}
1466+
if(c.valueArgumentsCount < 1) {
1467+
logger.warnElement(Severity.ErrorSevere, "No RHS found", c)
1468+
} else {
1469+
if(c.valueArgumentsCount > 1) {
1470+
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
1471+
}
1472+
val arg = c.getValueArgument(0)
1473+
if(arg == null) {
1474+
logger.warnElement(Severity.ErrorSevere, "RHS null", c)
1475+
} else {
1476+
extractExpressionExpr(arg, callable, id, 1)
1477+
}
1478+
}
1479+
}
1480+
1481+
fun binop(id: Label<out DbExpr>) {
1482+
val locId = tw.getLocation(c)
1483+
tw.writeHasLocation(id, locId)
1484+
tw.writeCallableEnclosingExpr(id, callable)
1485+
1486+
val dr = c.dispatchReceiver
1487+
if(dr != null) {
1488+
logger.warnElement(Severity.ErrorSevere, "Unexpected dispatch receiver found", c)
1489+
}
1490+
if(c.valueArgumentsCount < 1) {
1491+
logger.warnElement(Severity.ErrorSevere, "No arguments found", c)
1492+
} else {
1493+
val lhs = c.getValueArgument(0)
1494+
if(lhs == null) {
1495+
logger.warnElement(Severity.ErrorSevere, "LHS null", c)
1496+
} else {
1497+
extractExpressionExpr(lhs, callable, id, 0)
1498+
}
1499+
if(c.valueArgumentsCount < 2) {
1500+
logger.warnElement(Severity.ErrorSevere, "No RHS found", c)
1501+
} else {
1502+
val rhs = c.getValueArgument(1)
1503+
if(rhs == null) {
1504+
logger.warnElement(Severity.ErrorSevere, "RHS null", c)
1505+
} else {
1506+
extractExpressionExpr(rhs, callable, id, 1)
1507+
}
1508+
}
1509+
if(c.valueArgumentsCount > 2) {
1510+
logger.warnElement(Severity.ErrorSevere, "Extra arguments found", c)
1511+
}
1512+
}
1513+
}
1514+
1515+
when {
1516+
c.origin == PLUS &&
1517+
(isFunction("kotlin", "Int", "plus") || isFunction("kotlin", "String", "plus")) -> {
14191518
val id = tw.getFreshIdLabel<DbAddexpr>()
14201519
val type = useType(c.type)
1421-
val locId = tw.getLocation(c)
14221520
tw.writeExprs_addexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1423-
tw.writeHasLocation(id, locId)
1424-
tw.writeCallableEnclosingExpr(id, callable)
1521+
binopDisp(id)
14251522
id
14261523
}
1427-
MINUS -> {
1524+
c.origin == MINUS && isFunction("kotlin", "Int", "minus") -> {
14281525
val id = tw.getFreshIdLabel<DbSubexpr>()
14291526
val type = useType(c.type)
1430-
val locId = tw.getLocation(c)
14311527
tw.writeExprs_subexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1432-
tw.writeHasLocation(id, locId)
1433-
tw.writeCallableEnclosingExpr(id, callable)
1528+
binopDisp(id)
14341529
id
14351530
}
1436-
DIV -> {
1531+
c.origin == DIV && isFunction("kotlin", "Int", "div") -> {
14371532
val id = tw.getFreshIdLabel<DbDivexpr>()
14381533
val type = useType(c.type)
1439-
val locId = tw.getLocation(c)
14401534
tw.writeExprs_divexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1441-
tw.writeHasLocation(id, locId)
1442-
tw.writeCallableEnclosingExpr(id, callable)
1535+
binopDisp(id)
14431536
id
14441537
}
1445-
PERC -> {
1538+
c.origin == PERC && isFunction("kotlin", "Int", "rem") -> {
14461539
val id = tw.getFreshIdLabel<DbRemexpr>()
14471540
val type = useType(c.type)
1448-
val locId = tw.getLocation(c)
14491541
tw.writeExprs_remexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1450-
tw.writeHasLocation(id, locId)
1451-
tw.writeCallableEnclosingExpr(id, callable)
1542+
binopDisp(id)
14521543
id
14531544
}
1454-
EQEQ -> {
1545+
c.origin == EQEQ && isFunction("kotlin.internal.ir", null, "EQEQ") -> {
14551546
val id = tw.getFreshIdLabel<DbEqexpr>()
14561547
val type = useType(c.type)
1457-
val locId = tw.getLocation(c)
14581548
tw.writeExprs_eqexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1459-
tw.writeHasLocation(id, locId)
1460-
tw.writeCallableEnclosingExpr(id, callable)
1549+
binop(id)
14611550
id
14621551
}
1463-
EXCLEQ -> {
1552+
/*
1553+
TODO
1554+
c.origin == EXCLEQ -> {
14641555
val id = tw.getFreshIdLabel<DbNeexpr>()
14651556
val type = useType(c.type)
14661557
val locId = tw.getLocation(c)
@@ -1469,40 +1560,33 @@ open class KotlinFileExtractor(
14691560
tw.writeCallableEnclosingExpr(id, callable)
14701561
id
14711562
}
1472-
LT -> {
1563+
*/
1564+
c.origin == LT && isFunction("kotlin.internal.ir", null, "less") -> {
14731565
val id = tw.getFreshIdLabel<DbLtexpr>()
14741566
val type = useType(c.type)
1475-
val locId = tw.getLocation(c)
14761567
tw.writeExprs_ltexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1477-
tw.writeHasLocation(id, locId)
1478-
tw.writeCallableEnclosingExpr(id, callable)
1568+
binop(id)
14791569
id
14801570
}
1481-
LTEQ -> {
1571+
c.origin == LTEQ && isFunction("kotlin.internal.ir", null, "lessOrEqual") -> {
14821572
val id = tw.getFreshIdLabel<DbLeexpr>()
14831573
val type = useType(c.type)
1484-
val locId = tw.getLocation(c)
14851574
tw.writeExprs_leexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1486-
tw.writeHasLocation(id, locId)
1487-
tw.writeCallableEnclosingExpr(id, callable)
1575+
binop(id)
14881576
id
14891577
}
1490-
GT -> {
1578+
c.origin == GT && isFunction("kotlin.internal.ir", null, "greater") -> {
14911579
val id = tw.getFreshIdLabel<DbGtexpr>()
14921580
val type = useType(c.type)
1493-
val locId = tw.getLocation(c)
14941581
tw.writeExprs_gtexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1495-
tw.writeHasLocation(id, locId)
1496-
tw.writeCallableEnclosingExpr(id, callable)
1582+
binop(id)
14971583
id
14981584
}
1499-
GTEQ -> {
1585+
c.origin == GTEQ && isFunction("kotlin.internal.ir", null, "greaterOrEqual") -> {
15001586
val id = tw.getFreshIdLabel<DbGeexpr>()
15011587
val type = useType(c.type)
1502-
val locId = tw.getLocation(c)
15031588
tw.writeExprs_geexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1504-
tw.writeHasLocation(id, locId)
1505-
tw.writeCallableEnclosingExpr(id, callable)
1589+
binop(id)
15061590
id
15071591
}
15081592
else -> {
@@ -1518,16 +1602,17 @@ open class KotlinFileExtractor(
15181602
// type arguments at index -2, -3, ...
15191603
extractTypeArguments(c, id, callable, -2, true)
15201604
id
1521-
}
1522-
}
1523-
val dr = c.dispatchReceiver
1524-
if(dr != null) {
1525-
extractExpressionExpr(dr, callable, exprId, -1)
1526-
}
1527-
for(i in 0 until c.valueArgumentsCount) {
1528-
val arg = c.getValueArgument(i)
1529-
if(arg != null) {
1530-
extractExpressionExpr(arg, callable, exprId, i)
1605+
1606+
val dr = c.dispatchReceiver
1607+
if(dr != null) {
1608+
extractExpressionExpr(dr, callable, id, -1)
1609+
}
1610+
for(i in 0 until c.valueArgumentsCount) {
1611+
val arg = c.getValueArgument(i)
1612+
if(arg != null) {
1613+
extractExpressionExpr(arg, callable, id, i)
1614+
}
1615+
}
15311616
}
15321617
}
15331618
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
| exprs.kt:6:14:6:18 | ... + ... | exprs.kt:6:14:6:14 | x | exprs.kt:6:18:6:18 | y |
2+
| exprs.kt:7:14:7:18 | ... - ... | exprs.kt:7:14:7:14 | x | exprs.kt:7:18:7:18 | y |
3+
| exprs.kt:8:14:8:18 | ... / ... | exprs.kt:8:14:8:14 | x | exprs.kt:8:18:8:18 | y |
4+
| exprs.kt:9:14:9:18 | ... % ... | exprs.kt:9:14:9:14 | x | exprs.kt:9:18:9:18 | y |
5+
| exprs.kt:20:15:20:20 | ... == ... | exprs.kt:20:15:20:15 | x | exprs.kt:20:20:20:20 | y |
6+
| exprs.kt:22:15:22:19 | ... < ... | exprs.kt:22:15:22:15 | x | exprs.kt:22:19:22:19 | y |
7+
| exprs.kt:23:15:23:20 | ... <= ... | exprs.kt:23:15:23:15 | x | exprs.kt:23:20:23:20 | y |
8+
| exprs.kt:24:15:24:19 | ... > ... | exprs.kt:24:15:24:15 | x | exprs.kt:24:19:24:19 | y |
9+
| exprs.kt:25:15:25:20 | ... >= ... | exprs.kt:25:15:25:15 | x | exprs.kt:25:20:25:20 | y |
10+
| exprs.kt:50:16:50:26 | ... + ... | exprs.kt:50:16:50:19 | str1 | exprs.kt:50:23:50:26 | str2 |
11+
| exprs.kt:53:12:53:23 | ... > ... | exprs.kt:53:12:53:19 | variable | exprs.kt:53:23:53:23 | 0 |
12+
| exprs.kt:57:12:57:20 | ... + ... | exprs.kt:57:12:57:14 | 123 | exprs.kt:57:18:57:20 | 456 |
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
abstract Location getLocation();
10+
}
11+
12+
class YesMaybeElement extends MaybeElement {
13+
Element e;
14+
15+
YesMaybeElement() { this = TElement(e) }
16+
override string toString() { result = e.toString() }
17+
override Location getLocation() { result = e.getLocation() }
18+
}
19+
20+
class NoMaybeElement extends MaybeElement {
21+
NoMaybeElement() { this = TNoElement() }
22+
23+
override string toString() { result = "<none>" }
24+
override Location getLocation() { none() }
25+
}
26+
27+
MaybeElement lhs(BinaryExpr e) {
28+
if exists(e.getLeftOperand())
29+
then result = TElement(e.getLeftOperand())
30+
else result = TNoElement()
31+
}
32+
33+
MaybeElement rhs(BinaryExpr e) {
34+
if exists(e.getRightOperand())
35+
then result = TElement(e.getRightOperand())
36+
else result = TNoElement()
37+
}
38+
39+
from Expr e
40+
select e, lhs(e), rhs(e)

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

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@
2020
| exprs.kt:20:15:20:15 | x | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
2121
| exprs.kt:20:15:20:20 | ... == ... | exprs.kt:4:1:58:1 | topLevelMethod | EQExpr |
2222
| exprs.kt:20:20:20:20 | y | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
23-
| exprs.kt:21:5:21:20 | i14 | exprs.kt:4:1:58:1 | topLevelMethod | LocalVariableDeclExpr |
24-
| exprs.kt:21:15:21:15 | x | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
25-
| exprs.kt:21:15:21:20 | ... != ... | exprs.kt:4:1:58:1 | topLevelMethod | NEExpr |
26-
| exprs.kt:21:15:21:20 | ... != ... | exprs.kt:4:1:58:1 | topLevelMethod | NEExpr |
27-
| exprs.kt:21:20:21:20 | y | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
2823
| exprs.kt:22:5:22:19 | i15 | exprs.kt:4:1:58:1 | topLevelMethod | LocalVariableDeclExpr |
2924
| exprs.kt:22:15:22:15 | x | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
3025
| exprs.kt:22:15:22:19 | ... < ... | exprs.kt:4:1:58:1 | topLevelMethod | LTExpr |
@@ -76,16 +71,6 @@
7671
| exprs.kt:48:34:48:38 | bar | exprs.kt:4:1:58:1 | topLevelMethod | StringLiteral |
7772
| exprs.kt:48:40:48:43 | str2 | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
7873
| exprs.kt:48:44:48:47 | baz | exprs.kt:4:1:58:1 | topLevelMethod | StringLiteral |
79-
| exprs.kt:49:5:49:66 | str5 | exprs.kt:4:1:58:1 | topLevelMethod | LocalVariableDeclExpr |
80-
| exprs.kt:49:24:49:66 | "..." | exprs.kt:4:1:58:1 | topLevelMethod | StringTemplateExpr |
81-
| exprs.kt:49:25:49:28 | foo | exprs.kt:4:1:58:1 | topLevelMethod | StringLiteral |
82-
| exprs.kt:49:31:49:34 | str1 | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
83-
| exprs.kt:49:31:49:41 | ... + ... | exprs.kt:4:1:58:1 | topLevelMethod | AddExpr |
84-
| exprs.kt:49:38:49:41 | str2 | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
85-
| exprs.kt:49:43:49:47 | bar | exprs.kt:4:1:58:1 | topLevelMethod | StringLiteral |
86-
| exprs.kt:49:50:49:60 | ... + ... | exprs.kt:4:1:58:1 | topLevelMethod | AddExpr |
87-
| exprs.kt:49:57:49:60 | str1 | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
88-
| exprs.kt:49:62:49:65 | baz | exprs.kt:4:1:58:1 | topLevelMethod | StringLiteral |
8974
| exprs.kt:50:5:50:26 | str6 | exprs.kt:4:1:58:1 | topLevelMethod | LocalVariableDeclExpr |
9075
| exprs.kt:50:16:50:19 | str1 | exprs.kt:4:1:58:1 | topLevelMethod | VarAccess |
9176
| exprs.kt:50:16:50:26 | ... + ... | exprs.kt:4:1:58:1 | topLevelMethod | AddExpr |
@@ -152,19 +137,6 @@
152137
| exprs.kt:82:5:82:25 | r | exprs.kt:81:1:88:1 | foo | LocalVariableDeclExpr |
153138
| exprs.kt:82:13:82:13 | p | exprs.kt:81:1:88:1 | foo | VarAccess |
154139
| exprs.kt:82:15:82:25 | getBounds(...) | exprs.kt:81:1:88:1 | foo | MethodAccess |
155-
| exprs.kt:83:5:87:5 | when ... | exprs.kt:81:1:88:1 | foo | WhenExpr |
156-
| exprs.kt:83:8:83:8 | r | exprs.kt:81:1:88:1 | foo | VarAccess |
157-
| exprs.kt:83:8:83:16 | ... != ... | exprs.kt:81:1:88:1 | foo | NEExpr |
158-
| exprs.kt:83:8:83:16 | ... != ... | exprs.kt:81:1:88:1 | foo | NEExpr |
159-
| exprs.kt:83:13:83:16 | null | exprs.kt:81:1:88:1 | foo | NullLiteral |
160-
| exprs.kt:84:9:84:29 | r2 | exprs.kt:81:1:88:1 | foo | LocalVariableDeclExpr |
161-
| exprs.kt:84:29:84:29 | (...)... | exprs.kt:81:1:88:1 | foo | CastExpr |
162-
| exprs.kt:84:29:84:29 | Rectangle | exprs.kt:81:1:88:1 | foo | TypeAccess |
163-
| exprs.kt:84:29:84:29 | r | exprs.kt:81:1:88:1 | foo | VarAccess |
164-
| exprs.kt:85:9:85:30 | height | exprs.kt:81:1:88:1 | foo | LocalVariableDeclExpr |
165-
| exprs.kt:85:25:85:30 | height | exprs.kt:81:1:88:1 | foo | VarAccess |
166-
| exprs.kt:86:9:86:17 | ...=... | exprs.kt:81:1:88:1 | foo | AssignExpr |
167-
| exprs.kt:86:21:86:21 | 3 | exprs.kt:81:1:88:1 | foo | IntegerLiteral |
168140
| exprs.kt:90:1:92:1 | <obinit>(...) | exprs.kt:90:6:92:1 | Direction | MethodAccess |
169141
| exprs.kt:90:1:92:1 | new Enum(...) | exprs.kt:90:6:92:1 | Direction | ClassInstanceExpr |
170142
| exprs.kt:94:1:98:1 | <obinit>(...) | exprs.kt:94:6:98:1 | Color | MethodAccess |
@@ -179,7 +151,6 @@
179151
| exprs.kt:102:23:102:27 | GREEN | exprs.kt:100:1:103:1 | enums | VarAccess |
180152
| file://:0:0:0:0 | Color | exprs.kt:94:6:98:1 | Color | TypeAccess |
181153
| file://:0:0:0:0 | Direction | exprs.kt:90:6:92:1 | Direction | TypeAccess |
182-
| file://:0:0:0:0 | height | exprs.kt:81:1:88:1 | foo | VarAccess |
183154
| file://:0:0:0:0 | q | exprs.kt:72:1:79:1 | typeTests | VarAccess |
184155
| file://:0:0:0:0 | q | exprs.kt:72:1:79:1 | typeTests | VarAccess |
185156
| file://:0:0:0:0 | tmp0 | exprs.kt:4:1:58:1 | topLevelMethod | LocalVariableDeclExpr |

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ TODO
1818
val i12 = x.inv()
1919
*/
2020
val i13 = x == y
21-
val i14 = x != y
21+
// TODO val i14 = x != y
2222
val i15 = x < y
2323
val i16 = x <= y
2424
val i17 = x > y
@@ -46,7 +46,7 @@ TODO
4646
val str2: String? = "string lit"
4747
val str3: String? = null
4848
val str4: String = "foo $str1 bar $str2 baz"
49-
val str5: String = "foo ${str1 + str2} bar ${str2 + str1} baz"
49+
// TODO val str5: String = "foo ${str1 + str2} bar ${str2 + str1} baz"
5050
val str6 = str1 + str2
5151

5252
var variable = 10
@@ -80,11 +80,11 @@ fun typeTests(x: Root, y: Subclass1) {
8080

8181
fun foo(p: Polygon) {
8282
val r = p.getBounds()
83-
if(r != null) {
84-
val r2: Rectangle = r
85-
val height = r2.height
86-
r2.height = 3
87-
}
83+
// TODO if(r != null) {
84+
// TODO val r2: Rectangle = r
85+
// TODO val height = r2.height
86+
// TODO r2.height = 3
87+
// TODO }
8888
}
8989

9090
enum class Direction {

0 commit comments

Comments
 (0)