Skip to content

Commit 28d95f4

Browse files
committed
Kotlin: Implement and use fun <T,reified S: T> Iterable<T>.findSubType
We had a lot of uses of find which looked for a subtype, but then had to cast (seemingly unsafely) the result to that subtype. This pulls all the casts out into a utility function.
1 parent 51ada5c commit 28d95f4

File tree

2 files changed

+32
-21
lines changed

2 files changed

+32
-21
lines changed

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

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,7 @@ open class KotlinFileExtractor(
15681568
}
15691569
}
15701570

1571-
private fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.find { it is IrFunction && it.name.asString() == name } as IrFunction?
1571+
private fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.findSubType<IrDeclaration,IrFunction> { it.name.asString() == name }
15721572

15731573
val jvmIntrinsicsClass by lazy {
15741574
val result = pluginContext.referenceClass(FqName("kotlin.jvm.internal.Intrinsics"))?.owner
@@ -1625,22 +1625,21 @@ open class KotlinFileExtractor(
16251625
}
16261626

16271627
val stringValueOfObjectMethod by lazy {
1628-
val result = javaLangString?.declarations?.find {
1629-
it is IrFunction &&
1628+
val result = javaLangString?.declarations?.findSubType<IrDeclaration,IrFunction> {
16301629
it.name.asString() == "valueOf" &&
16311630
it.valueParameters.size == 1 &&
16321631
it.valueParameters[0].type == pluginContext.irBuiltIns.anyNType
1633-
} as IrFunction?
1632+
}
16341633
if (result == null) {
16351634
logger.error("Couldn't find declaration java.lang.String.valueOf(Object)")
16361635
}
16371636
result
16381637
}
16391638

16401639
val objectCloneMethod by lazy {
1641-
val result = javaLangObject?.declarations?.find {
1642-
it is IrFunction && it.name.asString() == "clone"
1643-
} as IrFunction?
1640+
val result = javaLangObject?.declarations?.findSubType<IrDeclaration,IrFunction> {
1641+
it.name.asString() == "clone"
1642+
}
16441643
if (result == null) {
16451644
logger.error("Couldn't find declaration java.lang.Object.clone(...)")
16461645
}
@@ -1654,10 +1653,9 @@ open class KotlinFileExtractor(
16541653
}
16551654

16561655
val kotlinNoWhenBranchMatchedConstructor by lazy {
1657-
val result = kotlinNoWhenBranchMatchedExn?.declarations?.find {
1658-
it is IrConstructor &&
1656+
val result = kotlinNoWhenBranchMatchedExn?.declarations?.findSubType<IrDeclaration,IrConstructor> {
16591657
it.valueParameters.isEmpty()
1660-
} as IrConstructor?
1658+
}
16611659
if (result == null) {
16621660
logger.error("Couldn't find no-arg constructor for kotlin.NoWhenBranchMatchedException")
16631661
}
@@ -1777,13 +1775,13 @@ open class KotlinFileExtractor(
17771775
return
17781776
}
17791777

1780-
val func = ((c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner as? IrClass)?.declarations?.find { it is IrFunction && it.name.asString() == fnName }
1778+
val func = ((c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner as? IrClass)?.declarations?.findSubType<IrDeclaration,IrFunction> { it.name.asString() == fnName }
17811779
if (func == null) {
17821780
logger.errorElement("Couldn't find function $fnName on enum type", c)
17831781
return
17841782
}
17851783

1786-
extractMethodAccess(func as IrFunction, false)
1784+
extractMethodAccess(func, false)
17871785
}
17881786

17891787
fun binopReceiver(id: Label<out DbExpr>, receiver: IrExpression?, receiverDescription: String) {
@@ -2227,10 +2225,10 @@ open class KotlinFileExtractor(
22272225
logger.errorElement("Argument to dataClassArrayMemberToString not a class", c)
22282226
return
22292227
}
2230-
val realCallee = javaUtilArrays?.declarations?.find { decl ->
2231-
decl is IrFunction && decl.name.asString() == "toString" && decl.valueParameters.size == 1 &&
2228+
val realCallee = javaUtilArrays?.declarations?.findSubType<IrDeclaration,IrFunction> { decl ->
2229+
decl.name.asString() == "toString" && decl.valueParameters.size == 1 &&
22322230
decl.valueParameters[0].type.classOrNull?.let { it == realArrayClass } == true
2233-
} as IrFunction?
2231+
}
22342232
if (realCallee == null) {
22352233
logger.errorElement("Couldn't find a java.lang.Arrays.toString method matching class ${realArrayClass.owner.name}", c)
22362234
} else {
@@ -2254,10 +2252,10 @@ open class KotlinFileExtractor(
22542252
logger.errorElement("Argument to dataClassArrayMemberHashCode not a class", c)
22552253
return
22562254
}
2257-
val realCallee = javaUtilArrays?.declarations?.find { decl ->
2258-
decl is IrFunction && decl.name.asString() == "hashCode" && decl.valueParameters.size == 1 &&
2255+
val realCallee = javaUtilArrays?.declarations?.findSubType<IrDeclaration,IrFunction> { decl ->
2256+
decl.name.asString() == "hashCode" && decl.valueParameters.size == 1 &&
22592257
decl.valueParameters[0].type.classOrNull?.let { it == realArrayClass } == true
2260-
} as IrFunction?
2258+
}
22612259
if (realCallee == null) {
22622260
logger.errorElement("Couldn't find a java.lang.Arrays.hashCode method matching class ${realArrayClass.owner.name}", c)
22632261
} else {
@@ -4365,7 +4363,7 @@ open class KotlinFileExtractor(
43654363
return
43664364
}
43674365

4368-
val invokeMethod = functionType.classOrNull?.owner?.declarations?.filterIsInstance<IrFunction>()?.find { it.name.asString() == OperatorNameConventions.INVOKE.asString()}
4366+
val invokeMethod = functionType.classOrNull?.owner?.declarations?.findSubType<IrDeclaration,IrFunction> { it.name.asString() == OperatorNameConventions.INVOKE.asString()}
43694367
if (invokeMethod == null) {
43704368
logger.errorElement("Couldn't find `invoke` method on functional interface.", e)
43714369
return
@@ -4376,7 +4374,7 @@ open class KotlinFileExtractor(
43764374
logger.errorElement("Expected to find SAM conversion to IrClass. Found '${typeOwner.javaClass}' instead. Can't implement SAM interface.", e)
43774375
return
43784376
}
4379-
val samMember = typeOwner.declarations.filterIsInstance<IrFunction>().find { it is IrOverridableMember && it.modality == Modality.ABSTRACT }
4377+
val samMember = typeOwner.declarations.findSubType<IrDeclaration,IrFunction> { it is IrOverridableMember && it.modality == Modality.ABSTRACT }
43804378
if (samMember == null) {
43814379
logger.errorElement("Couldn't find SAM member in type '${typeOwner.kotlinFqName.asString()}'. Can't implement SAM interface.", e)
43824380
return
@@ -4565,7 +4563,7 @@ open class KotlinFileExtractor(
45654563
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
45664564
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor)
45674565

4568-
val baseConstructor = baseClass.owner.declarations.find { it is IrFunction && it.symbol is IrConstructorSymbol }
4566+
val baseConstructor = baseClass.owner.declarations.findSubType<IrDeclaration,IrFunction> { it.symbol is IrConstructorSymbol }
45694567
val baseConstructorId = useFunction<DbConstructor>(baseConstructor as IrFunction)
45704568

45714569
tw.writeHasLocation(superCallId, locId)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.github.codeql
2+
3+
/**
4+
* This behaves the same as Iterable<T>.find, but requires
5+
* that the value found is of the subtype S, and it casts
6+
* the result for you appropriately.
7+
*/
8+
inline fun <T,reified S: T> Iterable<T>.findSubType(
9+
predicate: (S) -> Boolean
10+
): S? {
11+
return this.find { it is S && predicate(it) } as S?
12+
}
13+

0 commit comments

Comments
 (0)