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

Skip to content

Commit b66a314

Browse files
tamasvajkigfoo
authored andcommitted
Extract functions using their name from JvmName annotation
1 parent a24753f commit b66a314

9 files changed

Lines changed: 98 additions & 20 deletions

File tree

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,12 +721,16 @@ open class KotlinFileExtractor(
721721
val returnType = useType(substReturnType, TypeContext.RETURN)
722722
val shortName = getFunctionShortName(f)
723723
val methodId = id.cast<DbMethod>()
724-
tw.writeMethods(methodId, shortName, "$shortName$paramsSignature", returnType.javaResult.id, parentId, sourceDeclaration.cast<DbMethod>())
724+
tw.writeMethods(methodId, shortName.nameInDB, "${shortName.nameInDB}$paramsSignature", returnType.javaResult.id, parentId, sourceDeclaration.cast<DbMethod>())
725725
tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id)
726726

727727
if (!isExternalDeclaration(f)) {
728728
extractTypeAccessRecursive(f.returnType, locId, id, -1)
729729
}
730+
731+
if (shortName.nameInDB != shortName.kotlinName) {
732+
tw.writeKtFunctionOriginalNames(methodId, shortName.kotlinName)
733+
}
730734
}
731735

732736
tw.writeHasLocation(id, locId)

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

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.semmle.extractor.java.OdasaOutput
66
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
77
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
88
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
9+
import org.jetbrains.kotlin.descriptors.ClassKind
910
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
1011
import org.jetbrains.kotlin.ir.declarations.*
1112
import org.jetbrains.kotlin.ir.expressions.IrConst
@@ -48,29 +49,33 @@ open class KotlinUsesExtractor(
4849
TypeResult(fakeKotlinType(), "", "")
4950
)
5051

51-
@OptIn(kotlin.ExperimentalStdlibApi::class) // Annotation required by kotlin versions < 1.5
52-
fun extractFileClass(f: IrFile): Label<out DbClass> {
53-
val fileName = f.fileEntry.name
54-
val pkg = f.fqName.asString()
55-
val defaultName = fileName.replaceFirst(Regex(""".*[/\\]"""), "").replaceFirst(Regex("""\.kt$"""), "").replaceFirstChar({ it.uppercase() }) + "Kt"
56-
var jvmName = defaultName
57-
for(a: IrConstructorCall in f.annotations) {
52+
fun getJvmName(container: IrAnnotationContainer): String? {
53+
for(a: IrConstructorCall in container.annotations) {
5854
val t = a.type
59-
if(t is IrSimpleType && a.valueArgumentsCount == 1) {
55+
if (t is IrSimpleType && a.valueArgumentsCount == 1) {
6056
val owner = t.classifier.owner
6157
val v = a.getValueArgument(0)
62-
if(owner is IrClass) {
58+
if (owner is IrClass) {
6359
val aPkg = owner.packageFqName?.asString()
6460
val name = owner.name.asString()
6561
if(aPkg == "kotlin.jvm" && name == "JvmName" && v is IrConst<*>) {
6662
val value = v.value
67-
if(value is String) {
68-
jvmName = value
63+
if (value is String) {
64+
return value
6965
}
7066
}
7167
}
7268
}
7369
}
70+
return null
71+
}
72+
73+
@OptIn(kotlin.ExperimentalStdlibApi::class) // Annotation required by kotlin versions < 1.5
74+
fun extractFileClass(f: IrFile): Label<out DbClass> {
75+
val fileName = f.fileEntry.name
76+
val pkg = f.fqName.asString()
77+
val defaultName = fileName.replaceFirst(Regex(""".*[/\\]"""), "").replaceFirst(Regex("""\.kt$"""), "").replaceFirstChar({ it.uppercase() }) + "Kt"
78+
var jvmName = getJvmName(f) ?: defaultName
7479
val qualClassName = if (pkg.isEmpty()) jvmName else "$pkg.$jvmName"
7580
val label = "@\"class;$qualClassName\""
7681
val id: Label<DbClass> = tw.getLabelFor(label, {
@@ -668,22 +673,39 @@ open class KotlinUsesExtractor(
668673

669674
private val IrDeclaration.isAnonymousFunction get() = this is IrSimpleFunction && name == SpecialNames.NO_NAME_PROVIDED
670675

671-
fun getFunctionShortName(f: IrFunction) : String {
676+
data class FunctionNames(val nameInDB: String, val kotlinName: String)
677+
678+
fun getFunctionShortName(f: IrFunction) : FunctionNames {
672679
if (f.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || f.isAnonymousFunction)
673-
return OperatorNameConventions.INVOKE.asString()
680+
return FunctionNames(
681+
OperatorNameConventions.INVOKE.asString(),
682+
OperatorNameConventions.INVOKE.asString())
674683
(f as? IrSimpleFunction)?.correspondingPropertySymbol?.let {
675684
val propName = it.owner.name.asString()
676-
when(f) {
677-
it.owner.getter -> return JvmAbi.getterName(propName)
678-
it.owner.setter -> return JvmAbi.setterName(propName)
685+
val getter = it.owner.getter
686+
val setter = it.owner.setter
687+
688+
if (it.owner.parentClassOrNull?.kind == ClassKind.ANNOTATION_CLASS) {
689+
if (getter == null) {
690+
logger.error("Expected to find a getter for a property inside an annotation class")
691+
return FunctionNames(propName, propName)
692+
} else {
693+
val jvmName = getJvmName(getter)
694+
return FunctionNames(jvmName ?: propName, propName)
695+
}
696+
}
697+
698+
when (f) {
699+
getter -> return FunctionNames(getJvmName(getter) ?: JvmAbi.getterName(propName), JvmAbi.getterName(propName))
700+
setter -> return FunctionNames(getJvmName(setter) ?: JvmAbi.setterName(propName), JvmAbi.setterName(propName))
679701
else -> {
680702
logger.error(
681703
"Function has a corresponding property, but is neither the getter nor the setter"
682704
)
683705
}
684706
}
685707
}
686-
return f.name.asString()
708+
return FunctionNames(getJvmName(f) ?: f.name.asString(), f.name.asString())
687709
}
688710

689711
// This excludes class type parameters that show up in (at least) constructors' typeParameters list.
@@ -727,7 +749,7 @@ open class KotlinUsesExtractor(
727749
* allow it to be passed in.
728750
*/
729751
fun getFunctionLabel(f: IrFunction, maybeParentId: Label<out DbElement>?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
730-
getFunctionLabel(f.parent, maybeParentId, getFunctionShortName(f), f.valueParameters, f.returnType, f.extensionReceiverParameter, getFunctionTypeParameters(f), classTypeArgsIncludingOuterClasses)
752+
getFunctionLabel(f.parent, maybeParentId, getFunctionShortName(f).nameInDB, f.valueParameters, f.returnType, f.extensionReceiverParameter, getFunctionTypeParameters(f), classTypeArgsIncludingOuterClasses)
731753

732754
/*
733755
* This function actually generates the label for a function.

java/ql/lib/config/semmlecode.dbscheme

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,3 +1228,8 @@ compiler_generated(
12281228
int kind: int ref
12291229
// 1: Declaring classes of adapter functions in Kotlin
12301230
)
1231+
1232+
ktFunctionOriginalNames(
1233+
unique int id: @method ref,
1234+
string name: string ref
1235+
)

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,17 @@ class Method extends Callable, @method {
466466
/** Holds if this method is a Kotlin local function. */
467467
predicate isLocal() { ktLocalFunction(this) }
468468

469+
/**
470+
* Gets the Kotlin name of this method, that is either the name of this method, or
471+
* if `JvmName` annotation was applied to the declaration, then the original name.
472+
*/
473+
string getKotlinName() {
474+
ktFunctionOriginalNames(this, result)
475+
or
476+
not exists(string n | ktFunctionOriginalNames(this, n)) and
477+
result = this.getName()
478+
}
479+
469480
override string getAPrimaryQlClass() { result = "Method" }
470481
}
471482

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class Test {
2+
public void m() {
3+
int i = new X().getX_prop();
4+
}
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| Test.java:2:17:2:17 | m | m | m |
2+
| test.kt:4:9:4:18 | getX_prop | getX_prop | getX |
3+
| test.kt:6:5:6:19 | getX | getX | getX |
4+
| test.kt:10:5:10:19 | changeY | changeY | setY |
5+
| test.kt:10:5:10:19 | y | y | getY |
6+
| test.kt:13:5:13:15 | method | method | fn |
7+
| test.kt:17:5:17:14 | p | p | p |
8+
| test.kt:18:23:18:32 | w | w | q |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class X {
2+
val x: Int
3+
@JvmName("getX_prop")
4+
get() = 15
5+
6+
fun getX() = 10
7+
8+
@get:JvmName("y")
9+
@set:JvmName("changeY")
10+
var y: Int = 23
11+
12+
@JvmName("method")
13+
fun fn() {}
14+
}
15+
16+
annotation class Ann(
17+
val p: Int,
18+
@get:JvmName("w") val q: Int)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import java
2+
3+
query predicate names(Method m, string name, string kotlinName) {
4+
m.fromSource() and name = m.getName() and kotlinName = m.getKotlinName()
5+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
| file1.kt:4:18:4:23 | fun2(...) | file2.kt:3:5:3:18 | fun2 | Class2.fun2 | file2.kt:2:1:4:1 | Class2 |
22
| file1.kt:5:9:5:14 | fun3(...) | file3.kt:5:1:6:1 | fun3 | MyJvmName.fun3 | file3.kt:0:0:0:0 | MyJvmName |
33
| file1.kt:6:9:6:14 | fun4(...) | file4.kt:4:1:5:1 | fun4 | File4Kt.fun4 | file4.kt:0:0:0:0 | File4Kt |
4-
| file1.kt:11:29:11:56 | collectionToArray(...) | file://<external>/CollectionToArray.class:0:0:0:0 | collectionToArray | CollectionToArray.collectionToArray | file://<external>/CollectionToArray.class:0:0:0:0 | CollectionToArray |
4+
| file1.kt:11:29:11:56 | toArray(...) | file://<external>/CollectionToArray.class:0:0:0:0 | toArray | CollectionToArray.toArray | file://<external>/CollectionToArray.class:0:0:0:0 | CollectionToArray |
55
| file1.kt:11:47:11:55 | listOf(...) | file://<external>/CollectionsKt.class:0:0:0:0 | listOf | CollectionsKt.listOf | file://<external>/CollectionsKt.class:0:0:0:0 | CollectionsKt |

0 commit comments

Comments
 (0)