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

Skip to content

Commit 1b7e33b

Browse files
smowtonigfoo
authored andcommitted
Remove Kotlin element and component type from arrays
Now that these are no longer required, array extraction can extract kt-types consistently with other parameterised classes.
1 parent 70294bd commit 1b7e33b

6 files changed

Lines changed: 70 additions & 60 deletions

File tree

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

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import java.util.zip.GZIPOutputStream
2525
import com.semmle.extractor.java.OdasaOutput
2626
import com.semmle.extractor.java.OdasaOutput.TrapFileManager
2727
import com.semmle.util.files.FileUtil
28+
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
2829
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
2930
import org.jetbrains.kotlin.ir.util.*
3031
import kotlin.system.exitProcess
@@ -372,6 +373,8 @@ open class KotlinUsesExtractor(
372373
d.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
373374
}
374375

376+
fun isArray(t: IrSimpleType) = t.isBoxedArray || t.isPrimitiveArray()
377+
375378
fun extractClassLaterIfExternal(c: IrClass) {
376379
if (isExternalDeclaration(c)) {
377380
extractExternalClassLater(c)
@@ -410,7 +413,7 @@ open class KotlinUsesExtractor(
410413
else
411414
primitiveInfo.primitiveName
412415

413-
type.isBoxedArray || type.isPrimitiveArray() -> {
416+
isArray(type) -> {
414417
val elementType = type.getArrayElementType(pluginContext.irBuiltIns)
415418
val javaElementType = if (type.isPrimitiveArray()) elementType else elementType.makeNullable()
416419
shortName(javaElementType) + "[]"
@@ -520,22 +523,52 @@ open class KotlinUsesExtractor(
520523
return TypeResults(javaResult, kotlinResult)
521524
}
522525

523-
fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int): TypeResults {
526+
// Given either a primitive array or a boxed array, returns primitive arrays unchanged,
527+
// but returns boxed arrays with a nullable, invariant component type, with any nested arrays
528+
// similarly transformed. For example, Array<out Array<in E>> would become Array<Array<E?>?>
529+
// Array<*> will become Array<Any?>.
530+
fun getInvariantNullableArrayType(arrayType: IrSimpleType): IrSimpleType =
531+
if (arrayType.isPrimitiveArray())
532+
arrayType
533+
else {
534+
val componentType = arrayType.getArrayElementType(pluginContext.irBuiltIns)
535+
val componentTypeBroadened = when (componentType) {
536+
is IrSimpleType ->
537+
if (isArray(componentType)) getInvariantNullableArrayType(componentType) else componentType
538+
else -> componentType
539+
}
540+
val unchanged =
541+
componentType == componentTypeBroadened &&
542+
(arrayType.arguments[0] as? IrTypeProjection)?.variance == Variance.INVARIANT &&
543+
componentType.isNullable()
544+
if (unchanged)
545+
arrayType
546+
else
547+
IrSimpleTypeImpl(
548+
arrayType.classifier,
549+
true,
550+
listOf(makeTypeProjection(componentTypeBroadened, Variance.INVARIANT)),
551+
listOf()
552+
)
553+
}
554+
555+
fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int, isPrimitiveArray: Boolean): TypeResults {
556+
557+
// Ensure we extract Array<Int> as Integer[], not int[], for example:
558+
fun nullableIfNotPrimitive(type: IrType) = if (type.isPrimitiveType() && !isPrimitiveArray) type.makeNullable() else type
524559

525560
// TODO: Figure out what signatures should be returned
526561

527-
val componentTypeLabels = useType(componentType)
528-
val elementTypeLabels = useType(elementType)
562+
val componentTypeLabel = useType(nullableIfNotPrimitive(componentType)).javaResult.id
563+
val elementTypeLabel = useType(nullableIfNotPrimitive(elementType)).javaResult.id
529564

530-
val id = tw.getLabelFor<DbArray>("@\"array;$dimensions;{${elementTypeLabels.javaResult.id}}\"") {
565+
val id = tw.getLabelFor<DbArray>("@\"array;$dimensions;{${elementTypeLabel}}\"") {
531566
tw.writeArrays(
532567
it,
533568
shortName(arrayType),
534-
elementTypeLabels.javaResult.id,
535-
elementTypeLabels.kotlinResult.id,
569+
elementTypeLabel,
536570
dimensions,
537-
componentTypeLabels.javaResult.id,
538-
componentTypeLabels.kotlinResult.id)
571+
componentTypeLabel)
539572

540573
extractClassCommon(arrayType.classifier.owner as IrClass, it)
541574

@@ -546,29 +579,23 @@ open class KotlinUsesExtractor(
546579
// TODO: modifiers
547580
// tw.writeHasModifier(length, getModifierKey("public"))
548581
// tw.writeHasModifier(length, getModifierKey("final"))
549-
}
550582

551-
val javaSignature = "an array" // TODO: Wrong
552-
val javaResult = TypeResult(id, javaSignature)
553-
// Note the stripping of any type projection from `componentType` here mirrors the action of `IrType.getArrayElementType`,
554-
// and is required if we are not to produce different kotlin types for the same Java type (e.g. List[] -> Array<out List> or Array<List>)
555-
val owner: IrClass = arrayType.classifier.owner as IrClass
556-
val kotlinTypeArgs = if (arrayType.arguments.isEmpty()) listOf() else listOf(makeTypeProjection(componentType, Variance.INVARIANT))
557-
val kotlinClassName = getUnquotedClassLabel(owner, kotlinTypeArgs)
558-
val kotlinSignature = "$javaSignature?" // TODO: Wrong
559-
val kotlinLabel = "@\"kt_type;nullable;${kotlinClassName}\""
560-
val kotlinId: Label<DbKt_nullable_type> = tw.getLabelFor(kotlinLabel, {
561-
tw.writeKt_nullable_types(it, id)
562-
})
563-
val kotlinResult = TypeResult(kotlinId, kotlinSignature)
583+
// Note we will only emit one `clone()` method per Java array type, so we choose `Array<C?>` as its Kotlin
584+
// return type, where C is the component type with any nested arrays themselves invariant and nullable.
585+
val kotlinCloneReturnType = getInvariantNullableArrayType(arrayType).makeNullable()
586+
val kotlinCloneReturnTypeLabel = useType(kotlinCloneReturnType).kotlinResult.id
564587

565-
tw.getLabelFor<DbMethod>("@\"callable;{$id}.clone(){$id}\"") {
566-
tw.writeMethods(it, "clone", "clone()", javaResult.id, kotlinResult.id, javaResult.id, it)
588+
val clone = tw.getLabelFor<DbMethod>("@\"callable;{$it}.clone(){$it}\"")
589+
tw.writeMethods(clone, "clone", "clone()", it, kotlinCloneReturnTypeLabel, it, clone)
567590
// TODO: modifiers
568591
// tw.writeHasModifier(clone, getModifierKey("public"))
569592
}
570593

571-
return TypeResults(javaResult, kotlinResult)
594+
val javaSignature = "an array" // TODO: Wrong
595+
val javaResult = TypeResult(id, javaSignature)
596+
597+
val arrayClassResult = useSimpleTypeClass(arrayType.classifier.owner as IrClass, arrayType.arguments, arrayType.hasQuestionMark)
598+
return TypeResults(javaResult, arrayClassResult.kotlinResult)
572599
}
573600

574601
fun useSimpleType(s: IrSimpleType, canReturnPrimitiveTypes: Boolean): TypeResults {
@@ -669,13 +696,12 @@ class X {
669696
elementType = elementType.getArrayElementType(pluginContext.irBuiltIns)
670697
}
671698

672-
fun nullableUnlessPrimitive(type: IrType) = if (isPrimitiveArray && type.isPrimitiveType()) type else type.makeNullable()
673-
674699
return useArrayType(
675700
s,
676-
nullableUnlessPrimitive(componentType),
677-
nullableUnlessPrimitive(elementType),
678-
dimensions
701+
componentType,
702+
elementType,
703+
dimensions,
704+
isPrimitiveArray
679705
)
680706
}
681707

java/ql/lib/config/semmlecode.dbscheme

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,10 +512,8 @@ arrays(
512512
unique int id: @array,
513513
string nodeName: string ref,
514514
int elementtypeid: @type ref,
515-
int elementkttypeid: @kt_type ref,
516515
int dimension: int ref,
517-
int componenttypeid: @type ref,
518-
int componentkttypeid: @kt_type ref
516+
int componenttypeid: @type ref
519517
);
520518

521519
enclInReftype(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ predicate hasName(Element e, string name) {
4040
or
4141
wildcards(e, name, _)
4242
or
43-
arrays(e, name, _, _, _, _, _)
43+
arrays(e, name, _, _, _)
4444
or
4545
modifiers(e, name)
4646
or

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

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -354,35 +354,21 @@ class Array extends RefType, @array {
354354
*
355355
* For example, the component type of `Object[][]` is `Object[]`.
356356
*/
357-
Type getComponentType() { arrays(this, _, _, _, _, result, _) }
357+
Type getComponentType() { arrays(this, _, _, _, result) }
358358

359359
/**
360-
* Gets the type of the components of this array type.
361-
*
362-
* For example, the component type of `Object[][]` is `Object[]`.
363-
*/
364-
KotlinType getComponentKotlinType() { arrays(this, _, _, _, _, _, result) }
365-
366-
/**
367-
* Gets the Kotlin type of the elements used to construct this array type.
368-
*
369-
* For example, the element type of `Object[][]` is `Object`.
370-
*/
371-
Type getElementType() { arrays(this, _, result, _, _, _, _) }
372-
373-
/**
374-
* Gets the Kotlin type of the elements used to construct this array type.
360+
* Gets the type of the elements used to construct this array type.
375361
*
376362
* For example, the element type of `Object[][]` is `Object`.
377363
*/
378-
KotlinType getElementKotlinType() { arrays(this, _, _, result, _, _, _) }
364+
Type getElementType() { arrays(this, _, result, _, _) }
379365

380366
/**
381367
* Gets the arity of this array type.
382368
*
383369
* For example, the dimension of `Object[][]` is 2.
384370
*/
385-
int getDimension() { arrays(this, _, _, _, result, _, _) }
371+
int getDimension() { arrays(this, _, _, result, _) }
386372

387373
/**
388374
* Gets the JVM descriptor for this type, as used in bytecode.
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
| primitiveArrays.kt:5:12:5:24 | a | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Kotlin nullable Integer | file://:0:0:0:0 | Kotlin nullable Integer |
2-
| primitiveArrays.kt:5:27:5:40 | b | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Kotlin nullable Integer | file://:0:0:0:0 | Kotlin nullable Integer |
3-
| primitiveArrays.kt:5:43:5:53 | c | file://:0:0:0:0 | int[] | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | Kotlin not-null Integer | file://:0:0:0:0 | Kotlin not-null Integer |
4-
| primitiveArrays.kt:5:56:5:76 | d | file://:0:0:0:0 | Integer[][] | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Kotlin nullable Integer[] | file://:0:0:0:0 | Kotlin nullable Integer |
5-
| primitiveArrays.kt:5:79:5:98 | e | file://:0:0:0:0 | Integer[][] | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Kotlin nullable Integer[] | file://:0:0:0:0 | Kotlin nullable Integer |
6-
| primitiveArrays.kt:5:101:5:118 | f | file://:0:0:0:0 | int[][] | file://:0:0:0:0 | int[] | file://:0:0:0:0 | int | file://:0:0:0:0 | Kotlin nullable int[] | file://:0:0:0:0 | Kotlin not-null Integer |
1+
| primitiveArrays.kt:5:12:5:24 | a | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Integer |
2+
| primitiveArrays.kt:5:27:5:40 | b | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer | file://:0:0:0:0 | Integer |
3+
| primitiveArrays.kt:5:43:5:53 | c | file://:0:0:0:0 | int[] | file://:0:0:0:0 | int | file://:0:0:0:0 | int |
4+
| primitiveArrays.kt:5:56:5:76 | d | file://:0:0:0:0 | Integer[][] | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer |
5+
| primitiveArrays.kt:5:79:5:98 | e | file://:0:0:0:0 | Integer[][] | file://:0:0:0:0 | Integer[] | file://:0:0:0:0 | Integer |
6+
| primitiveArrays.kt:5:101:5:118 | f | file://:0:0:0:0 | int[][] | file://:0:0:0:0 | int[] | file://:0:0:0:0 | int |

java/ql/test/kotlin/library-tests/arrays/test.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import java
22

33
from Parameter p, Array a
44
where p.getType() = a and p.getFile().getBaseName() = "primitiveArrays.kt"
5-
select p, a, a.getComponentType(), a.getElementType(), a.getComponentKotlinType(), a.getElementKotlinType()
5+
select p, a, a.getComponentType(), a.getElementType()

0 commit comments

Comments
 (0)