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