Skip to content

Commit e1c43c6

Browse files
committed
Koltin: support collection literals
1 parent 5948126 commit e1c43c6

File tree

4 files changed

+166
-71
lines changed

4 files changed

+166
-71
lines changed

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

Lines changed: 80 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,7 +1736,7 @@ open class KotlinFileExtractor(
17361736
private fun extractsDefaultsCall(
17371737
syntacticCallTarget: IrFunction,
17381738
locId: Label<DbLocation>,
1739-
callsite: IrCall,
1739+
resultType: IrType,
17401740
enclosingCallable: Label<out DbCallable>,
17411741
callsiteParent: Label<out DbExprparent>,
17421742
childIdx: Int,
@@ -1751,7 +1751,7 @@ open class KotlinFileExtractor(
17511751
useFunction<DbCallable>(callTarget)
17521752
}
17531753
val defaultMethodLabel = getDefaultsMethodLabel(callTarget)
1754-
val id = extractMethodAccessWithoutArgs(callsite.type, locId, enclosingCallable, callsiteParent, childIdx, enclosingStmt, defaultMethodLabel)
1754+
val id = extractMethodAccessWithoutArgs(resultType, locId, enclosingCallable, callsiteParent, childIdx, enclosingStmt, defaultMethodLabel)
17551755

17561756
if (callTarget.isLocalFunction()) {
17571757
extractTypeAccess(getLocallyVisibleFunctionLabels(callTarget).type, locId, id, -1, enclosingCallable, enclosingStmt)
@@ -1854,7 +1854,8 @@ open class KotlinFileExtractor(
18541854

18551855
fun extractRawMethodAccess(
18561856
syntacticCallTarget: IrFunction,
1857-
callsite: IrCall,
1857+
locElement: IrElement,
1858+
resultType: IrType,
18581859
enclosingCallable: Label<out DbCallable>,
18591860
callsiteParent: Label<out DbExprparent>,
18601861
childIdx: Int,
@@ -1866,13 +1867,13 @@ open class KotlinFileExtractor(
18661867
extractClassTypeArguments: Boolean = false,
18671868
superQualifierSymbol: IrClassSymbol? = null) {
18681869

1869-
val locId = tw.getLocation(callsite)
1870+
val locId = tw.getLocation(locElement)
18701871

18711872
if (valueArguments.any { it == null }) {
18721873
extractsDefaultsCall(
18731874
syntacticCallTarget,
18741875
locId,
1875-
callsite,
1876+
resultType,
18761877
enclosingCallable,
18771878
callsiteParent,
18781879
childIdx,
@@ -1885,7 +1886,7 @@ open class KotlinFileExtractor(
18851886
extractRawMethodAccess(
18861887
syntacticCallTarget,
18871888
locId,
1888-
callsite.type,
1889+
resultType,
18891890
enclosingCallable,
18901891
callsiteParent,
18911892
childIdx,
@@ -2216,7 +2217,7 @@ open class KotlinFileExtractor(
22162217
return
22172218
}
22182219

2219-
extractRawMethodAccess(syntacticCallTarget, c, callable, parent, idx, enclosingStmt, (0 until c.valueArgumentsCount).map { c.getValueArgument(it) }, c.dispatchReceiver, c.extensionReceiver, typeArgs, extractClassTypeArguments, c.superQualifierSymbol)
2220+
extractRawMethodAccess(syntacticCallTarget, c, c.type, callable, parent, idx, enclosingStmt, (0 until c.valueArgumentsCount).map { c.getValueArgument(it) }, c.dispatchReceiver, c.extensionReceiver, typeArgs, extractClassTypeArguments, c.superQualifierSymbol)
22202221
}
22212222

22222223
fun extractSpecialEnumFunction(fnName: String){
@@ -2320,7 +2321,7 @@ open class KotlinFileExtractor(
23202321
}
23212322
isFunction(target, "kotlin", "String", "plus", true) -> {
23222323
findJdkIntrinsicOrWarn("stringPlus", c)?.let { stringPlusFn ->
2323-
extractRawMethodAccess(stringPlusFn, c, callable, parent, idx, enclosingStmt, listOf(c.extensionReceiver, c.getValueArgument(0)), null, null)
2324+
extractRawMethodAccess(stringPlusFn, c, c.type, callable, parent, idx, enclosingStmt, listOf(c.extensionReceiver, c.getValueArgument(0)), null, null)
23242325
}
23252326
}
23262327
isNumericFunction(target, listOf("plus", "minus", "times", "div", "rem", "and", "or", "xor", "shl", "shr", "ushr")) -> {
@@ -2562,7 +2563,7 @@ open class KotlinFileExtractor(
25622563
}
25632564
isFunction(target, "kotlin", "Any", "toString", true) -> {
25642565
stringValueOfObjectMethod?.let {
2565-
extractRawMethodAccess(it, c, callable, parent, idx, enclosingStmt, listOf(c.extensionReceiver), null, null)
2566+
extractRawMethodAccess(it, c, c.type, callable, parent, idx, enclosingStmt, listOf(c.extensionReceiver), null, null)
25662567
}
25672568
}
25682569
isBuiltinCallKotlin(c, "enumValues") -> {
@@ -2612,6 +2613,22 @@ open class KotlinFileExtractor(
26122613
|| isBuiltinCallKotlin(c, "byteArrayOf")
26132614
|| isBuiltinCallKotlin(c, "booleanArrayOf") -> {
26142615

2616+
// TODO: is there any reason not to always use getArrayElementType?
2617+
val elementType = if (isBuiltinCallKotlin(c, "arrayOf")) {
2618+
if (c.typeArgumentsCount == 1) {
2619+
c.getTypeArgument(0).also {
2620+
if (it == null) {
2621+
logger.errorElement("Type argument missing in an arrayOf call", c)
2622+
}
2623+
}
2624+
} else {
2625+
logger.errorElement("Expected to find one type argument in arrayOf call", c)
2626+
null
2627+
}
2628+
} else {
2629+
c.type.getArrayElementType(pluginContext.irBuiltIns)
2630+
}
2631+
26152632
val arg = if (c.valueArgumentsCount == 1) c.getValueArgument(0) else {
26162633
logger.errorElement("Expected to find only one (vararg) argument in ${c.symbol.owner.name.asString()} call", c)
26172634
null
@@ -2622,59 +2639,7 @@ open class KotlinFileExtractor(
26222639
}
26232640
}
26242641

2625-
// If this is [someType]ArrayOf(*x), x, otherwise null
2626-
val clonedArray = arg?.let {
2627-
if (arg.elements.size == 1) {
2628-
val onlyElement = arg.elements[0]
2629-
if (onlyElement is IrSpreadElement)
2630-
onlyElement.expression
2631-
else null
2632-
} else null
2633-
}
2634-
2635-
if (clonedArray != null) {
2636-
// This is an array clone: extract is as a call to java.lang.Object.clone
2637-
objectCloneMethod?.let {
2638-
extractRawMethodAccess(it, c, callable, parent, idx, enclosingStmt, listOf(), clonedArray, null)
2639-
}
2640-
} else {
2641-
// This is array creation: extract it as a call to new ArrayType[] { ... }
2642-
val id = tw.getFreshIdLabel<DbArraycreationexpr>()
2643-
val type = useType(c.type)
2644-
tw.writeExprs_arraycreationexpr(id, type.javaResult.id, parent, idx)
2645-
tw.writeExprsKotlinType(id, type.kotlinResult.id)
2646-
val locId = tw.getLocation(c)
2647-
tw.writeHasLocation(id, locId)
2648-
tw.writeCallableEnclosingExpr(id, callable)
2649-
2650-
if (isBuiltinCallKotlin(c, "arrayOf")) {
2651-
if (c.typeArgumentsCount == 1) {
2652-
val typeArgument = c.getTypeArgument(0)
2653-
if (typeArgument == null) {
2654-
logger.errorElement("Type argument missing in an arrayOf call", c)
2655-
} else {
2656-
extractTypeAccessRecursive(typeArgument, locId, id, -1, callable, enclosingStmt, TypeContext.GENERIC_ARGUMENT)
2657-
}
2658-
} else {
2659-
logger.errorElement("Expected to find one type argument in arrayOf call", c )
2660-
}
2661-
} else {
2662-
val elementType = c.type.getArrayElementType(pluginContext.irBuiltIns)
2663-
extractTypeAccessRecursive(elementType, locId, id, -1, callable, enclosingStmt)
2664-
}
2665-
2666-
arg?.let {
2667-
val initId = tw.getFreshIdLabel<DbArrayinit>()
2668-
tw.writeExprs_arrayinit(initId, type.javaResult.id, id, -2)
2669-
tw.writeExprsKotlinType(initId, type.kotlinResult.id)
2670-
tw.writeHasLocation(initId, locId)
2671-
tw.writeCallableEnclosingExpr(initId, callable)
2672-
tw.writeStatementEnclosingExpr(initId, enclosingStmt)
2673-
it.elements.forEachIndexed { i, arg -> extractVarargElement(arg, callable, initId, i, enclosingStmt) }
2674-
2675-
extractConstantInteger(it.elements.size, locId, id, 0, callable, enclosingStmt)
2676-
}
2677-
}
2642+
extractArrayCreation(arg, c.type, elementType, c, parent, idx, callable, enclosingStmt)
26782643
}
26792644
isBuiltinCall(c, "<get-java>", "kotlin.jvm") -> {
26802645
// Special case for KClass<*>.java, which is used in the Parcelize plugin. In normal cases, this is already rewritten to the property referenced below:
@@ -2694,7 +2659,7 @@ open class KotlinFileExtractor(
26942659
val argType = (ext.type as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull
26952660
val typeArguments = if (argType == null) listOf() else listOf(argType)
26962661

2697-
extractRawMethodAccess(getter, c, callable, parent, idx, enclosingStmt, listOf(), null, ext, typeArguments)
2662+
extractRawMethodAccess(getter, c, c.type, callable, parent, idx, enclosingStmt, listOf(), null, ext, typeArguments)
26982663
}
26992664
}
27002665
isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "iterator") -> {
@@ -2725,7 +2690,7 @@ open class KotlinFileExtractor(
27252690
else -> pluginContext.irBuiltIns.anyNType
27262691
}
27272692
}
2728-
extractRawMethodAccess(iteratorFn, c, callable, parent, idx, enclosingStmt, listOf(c.dispatchReceiver), null, null, typeArgs)
2693+
extractRawMethodAccess(iteratorFn, c, c.type, callable, parent, idx, enclosingStmt, listOf(c.dispatchReceiver), null, null, typeArgs)
27292694
}
27302695
}
27312696
}
@@ -2814,6 +2779,7 @@ open class KotlinFileExtractor(
28142779
extractRawMethodAccess(
28152780
realCallee,
28162781
c,
2782+
c.type,
28172783
callable,
28182784
parent,
28192785
idx,
@@ -2841,6 +2807,7 @@ open class KotlinFileExtractor(
28412807
extractRawMethodAccess(
28422808
realCallee,
28432809
c,
2810+
c.type,
28442811
callable,
28452812
parent,
28462813
idx,
@@ -2858,6 +2825,50 @@ open class KotlinFileExtractor(
28582825
}
28592826
}
28602827

2828+
private fun extractArrayCreation(elementList: IrVararg?, resultType: IrType, elementType: IrType?, locElement: IrElement, parent: Label<out DbExprparent>, idx: Int, enclosingCallable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) {
2829+
// If this is [someType]ArrayOf(*x), x, otherwise null
2830+
val clonedArray = elementList?.let {
2831+
if (it.elements.size == 1) {
2832+
val onlyElement = it.elements[0]
2833+
if (onlyElement is IrSpreadElement)
2834+
onlyElement.expression
2835+
else null
2836+
} else null
2837+
}
2838+
2839+
if (clonedArray != null) {
2840+
// This is an array clone: extract is as a call to java.lang.Object.clone
2841+
objectCloneMethod?.let {
2842+
extractRawMethodAccess(it, locElement, resultType, enclosingCallable, parent, idx, enclosingStmt, listOf(), clonedArray, null)
2843+
}
2844+
} else {
2845+
// This is array creation: extract it as a call to new ArrayType[] { ... }
2846+
val id = tw.getFreshIdLabel<DbArraycreationexpr>()
2847+
val type = useType(resultType)
2848+
tw.writeExprs_arraycreationexpr(id, type.javaResult.id, parent, idx)
2849+
tw.writeExprsKotlinType(id, type.kotlinResult.id)
2850+
val locId = tw.getLocation(locElement)
2851+
tw.writeHasLocation(id, locId)
2852+
tw.writeCallableEnclosingExpr(id, enclosingCallable)
2853+
2854+
if (elementType != null) {
2855+
extractTypeAccessRecursive(elementType, locId, id, -1, enclosingCallable, enclosingStmt, TypeContext.GENERIC_ARGUMENT)
2856+
}
2857+
2858+
if (elementList != null) {
2859+
val initId = tw.getFreshIdLabel<DbArrayinit>()
2860+
tw.writeExprs_arrayinit(initId, type.javaResult.id, id, -2)
2861+
tw.writeExprsKotlinType(initId, type.kotlinResult.id)
2862+
tw.writeHasLocation(initId, locId)
2863+
tw.writeCallableEnclosingExpr(initId, enclosingCallable)
2864+
tw.writeStatementEnclosingExpr(initId, enclosingStmt)
2865+
elementList.elements.forEachIndexed { i, arg -> extractVarargElement(arg, enclosingCallable, initId, i, enclosingStmt) }
2866+
2867+
extractConstantInteger(elementList.elements.size, locId, id, 0, enclosingCallable, enclosingStmt)
2868+
}
2869+
}
2870+
}
2871+
28612872
private fun extractNewExpr(
28622873
methodId: Label<out DbConstructor>,
28632874
constructedType: TypeResults,
@@ -3641,14 +3652,12 @@ open class KotlinFileExtractor(
36413652
extractTypeOperatorCall(e, callable, exprParent.parent, exprParent.idx, exprParent.enclosingStmt)
36423653
}
36433654
is IrVararg -> {
3644-
var spread = e.elements.getOrNull(0) as? IrSpreadElement
3645-
if (spread == null || e.elements.size != 1) {
3646-
logger.errorElement("Unexpected IrVararg", e)
3647-
return
3648-
}
36493655
// There are lowered IR cases when the vararg expression is not within a call, such as
3650-
// val temp0 = [*expr]
3651-
extractExpression(spread.expression, callable, parent)
3656+
// val temp0 = [*expr].
3657+
// This AST element can also occur as a collection literal in an annotation class, such as
3658+
// annotation class Ann(val strings: Array<String> = [])
3659+
val exprParent = parent.expr(e, callable)
3660+
extractArrayCreation(e, e.type, e.varargElementType, e, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt)
36523661
}
36533662
is IrGetObjectValue -> {
36543663
// For `object MyObject { ... }`, the .class has an
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
test.kt:
2+
# 0| [CompilationUnit] test
3+
# 1| 1: [Interface] Ann
4+
# 1| 1: [Constructor] Ann
5+
#-----| 4: (Parameters)
6+
# 1| 0: [Parameter] arr1
7+
# 1| 0: [TypeAccess] String[]
8+
# 1| 0: [TypeAccess] String
9+
# 1| 1: [Parameter] arr2
10+
# 1| 0: [TypeAccess] int[]
11+
# 1| 5: [BlockStmt] { ... }
12+
# 1| 0: [SuperConstructorInvocationStmt] super(...)
13+
# 1| 1: [BlockStmt] { ... }
14+
# 1| 0: [ExprStmt] <Expr>;
15+
# 1| 0: [KtInitializerAssignExpr] ...=...
16+
# 1| 0: [VarAccess] arr1
17+
# 1| 1: [ExprStmt] <Expr>;
18+
# 1| 0: [KtInitializerAssignExpr] ...=...
19+
# 1| 0: [VarAccess] arr2
20+
# 1| 2: [Constructor] Ann
21+
#-----| 4: (Parameters)
22+
# 1| 0: [Parameter] p0
23+
# 1| 0: [TypeAccess] String[]
24+
# 1| 1: [Parameter] p1
25+
# 1| 0: [TypeAccess] int[]
26+
# 1| 2: [Parameter] p2
27+
# 1| 0: [TypeAccess] int
28+
# 1| 3: [Parameter] p3
29+
# 1| 0: [TypeAccess] DefaultConstructorMarker
30+
# 1| 5: [BlockStmt] { ... }
31+
# 1| 0: [IfStmt] if (...)
32+
# 1| 0: [EQExpr] ... == ...
33+
# 1| 0: [AndBitwiseExpr] ... & ...
34+
# 1| 0: [IntegerLiteral] 1
35+
# 1| 1: [VarAccess] p2
36+
# 1| 1: [IntegerLiteral] 0
37+
# 1| 1: [ExprStmt] <Expr>;
38+
# 1| 0: [AssignExpr] ...=...
39+
# 1| 0: [VarAccess] p0
40+
# 0| 1: [ArrayCreationExpr] new String[]
41+
# 0| -2: [ArrayInit] {...}
42+
# 0| 0: [StringLiteral] hello
43+
# 0| 1: [StringLiteral] world
44+
# 0| -1: [TypeAccess] String
45+
# 0| 0: [IntegerLiteral] 2
46+
# 1| 1: [IfStmt] if (...)
47+
# 1| 0: [EQExpr] ... == ...
48+
# 1| 0: [AndBitwiseExpr] ... & ...
49+
# 1| 0: [IntegerLiteral] 2
50+
# 1| 1: [VarAccess] p2
51+
# 1| 1: [IntegerLiteral] 0
52+
# 1| 1: [ExprStmt] <Expr>;
53+
# 1| 0: [AssignExpr] ...=...
54+
# 1| 0: [VarAccess] p1
55+
# 0| 1: [ArrayCreationExpr] new int[]
56+
# 0| -2: [ArrayInit] {...}
57+
# 0| 0: [IntegerLiteral] 1
58+
# 0| 1: [IntegerLiteral] 2
59+
# 0| 2: [IntegerLiteral] 3
60+
# 0| -1: [TypeAccess] Integer
61+
# 0| 0: [IntegerLiteral] 3
62+
# 1| 2: [ThisConstructorInvocationStmt] this(...)
63+
# 1| 0: [VarAccess] p0
64+
# 1| 1: [VarAccess] p1
65+
# 1| 3: [FieldDeclaration] String[] arr1;
66+
# 1| -1: [TypeAccess] String[]
67+
# 1| 0: [TypeAccess] String
68+
# 1| 0: [VarAccess] arr1
69+
# 1| 4: [Method] arr1
70+
# 1| 3: [TypeAccess] String[]
71+
# 1| 0: [TypeAccess] String
72+
# 1| 5: [BlockStmt] { ... }
73+
# 1| 0: [ReturnStmt] return ...
74+
# 1| 0: [VarAccess] this.arr1
75+
# 1| -1: [ThisAccess] this
76+
# 1| 5: [Method] arr2
77+
# 1| 3: [TypeAccess] int[]
78+
# 1| 5: [BlockStmt] { ... }
79+
# 1| 0: [ReturnStmt] return ...
80+
# 1| 0: [VarAccess] this.arr2
81+
# 1| -1: [ThisAccess] this
82+
# 1| 6: [FieldDeclaration] int[] arr2;
83+
# 1| -1: [TypeAccess] int[]
84+
# 1| 0: [VarAccess] arr2
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle/code/java/PrintAst.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
annotation class Ann(val arr1: Array<String> = ["hello", "world"], val arr2: IntArray = [1, 2, 3]) { }

0 commit comments

Comments
 (0)