1+ package com.github.codeql.utils
2+
3+ import org.jetbrains.kotlin.backend.common.ir.allOverridden
4+ import org.jetbrains.kotlin.builtins.StandardNames
5+ import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
6+ import org.jetbrains.kotlin.ir.declarations.IrClass
7+ import org.jetbrains.kotlin.ir.declarations.IrFunction
8+ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
9+ import org.jetbrains.kotlin.ir.expressions.IrConst
10+ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
11+ import org.jetbrains.kotlin.ir.types.IrSimpleType
12+ import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
13+ import org.jetbrains.kotlin.ir.util.packageFqName
14+ import org.jetbrains.kotlin.ir.util.parentClassOrNull
15+ import org.jetbrains.kotlin.name.FqName
16+ import org.jetbrains.kotlin.name.Name
17+
18+ private data class MethodKey (val className : FqName , val functionName : Name )
19+
20+ private fun makeDescription (className : FqName , functionName : String ) = MethodKey (className, Name .guessByFirstCharacter(functionName))
21+
22+ // This essentially mirrors SpecialBridgeMethods.kt, a backend pass which isn't easily available to our extractor.
23+ private val specialFunctions = mapOf (
24+ makeDescription(StandardNames .FqNames .collection, " <get-size>" ) to " size" ,
25+ makeDescription(FqName (" java.util.Collection" ), " <get-size>" ) to " size" ,
26+ makeDescription(StandardNames .FqNames .map, " <get-size>" ) to " size" ,
27+ makeDescription(FqName (" java.util.Map" ), " <get-size>" ) to " size" ,
28+ makeDescription(StandardNames .FqNames .charSequence.toSafe(), " <get-length>" ) to " length" ,
29+ makeDescription(FqName (" java.lang.CharSequence" ), " <get-length>" ) to " length" ,
30+ makeDescription(StandardNames .FqNames .map, " <get-keys>" ) to " keySet" ,
31+ makeDescription(FqName (" java.util.Map" ), " <get-keys>" ) to " keySet" ,
32+ makeDescription(StandardNames .FqNames .map, " <get-values>" ) to " values" ,
33+ makeDescription(FqName (" java.util.Map" ), " <get-values>" ) to " values" ,
34+ makeDescription(StandardNames .FqNames .map, " <get-entries>" ) to " entrySet" ,
35+ makeDescription(FqName (" java.util.Map" ), " <get-entries>" ) to " entrySet" ,
36+ makeDescription(StandardNames .FqNames .mutableList, " removeAt" ) to " remove" ,
37+ makeDescription(FqName (" java.util.List" ), " removeAt" ) to " remove" ,
38+ makeDescription(StandardNames .FqNames ._enum .toSafe(), " <get-ordinal>" ) to " ordinal" ,
39+ makeDescription(FqName (" java.lang.Enum" ), " <get-ordinal>" ) to " ordinal" ,
40+ makeDescription(StandardNames .FqNames ._enum .toSafe(), " <get-name>" ) to " name" ,
41+ makeDescription(FqName (" java.lang.Enum" ), " <get-name>" ) to " name" ,
42+ makeDescription(StandardNames .FqNames .number.toSafe(), " toByte" ) to " byteValue" ,
43+ makeDescription(FqName (" java.lang.Number" ), " toByte" ) to " byteValue" ,
44+ makeDescription(StandardNames .FqNames .number.toSafe(), " toShort" ) to " shortValue" ,
45+ makeDescription(FqName (" java.lang.Number" ), " toShort" ) to " shortValue" ,
46+ makeDescription(StandardNames .FqNames .number.toSafe(), " toInt" ) to " intValue" ,
47+ makeDescription(FqName (" java.lang.Number" ), " toInt" ) to " intValue" ,
48+ makeDescription(StandardNames .FqNames .number.toSafe(), " toLong" ) to " longValue" ,
49+ makeDescription(FqName (" java.lang.Number" ), " toLong" ) to " longValue" ,
50+ makeDescription(StandardNames .FqNames .number.toSafe(), " toFloat" ) to " floatValue" ,
51+ makeDescription(FqName (" java.lang.Number" ), " toFloat" ) to " floatValue" ,
52+ makeDescription(StandardNames .FqNames .number.toSafe(), " toDouble" ) to " doubleValue" ,
53+ makeDescription(FqName (" java.lang.Number" ), " toDouble" ) to " doubleValue" ,
54+ )
55+
56+ private val specialFunctionShortNames = specialFunctions.keys.map { it.functionName }.toSet()
57+
58+ fun getSpecialJvmName (f : IrFunction ): String? {
59+ if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction ) {
60+ f.allOverridden(true ).forEach { overriddenFunc ->
61+ overriddenFunc.parentClassOrNull?.fqNameWhenAvailable?.let { parentFqName ->
62+ specialFunctions[MethodKey (parentFqName, f.name)]?.let {
63+ return it
64+ }
65+ }
66+ }
67+ }
68+ return null
69+ }
70+
71+ fun getJvmName (container : IrAnnotationContainer ): String? {
72+ for (a: IrConstructorCall in container.annotations) {
73+ val t = a.type
74+ if (t is IrSimpleType && a.valueArgumentsCount == 1 ) {
75+ val owner = t.classifier.owner
76+ val v = a.getValueArgument(0 )
77+ if (owner is IrClass ) {
78+ val aPkg = owner.packageFqName?.asString()
79+ val name = owner.name.asString()
80+ if (aPkg == " kotlin.jvm" && name == " JvmName" && v is IrConst <* >) {
81+ val value = v.value
82+ if (value is String ) {
83+ return value
84+ }
85+ }
86+ }
87+ }
88+ }
89+ return (container as ? IrFunction )?.let { getSpecialJvmName(container) }
90+ }
0 commit comments