Add PropertyRefExpr QL class, change extraction to use it, and add tests

This commit is contained in:
Tamas Vajk
2022-02-24 12:46:38 +01:00
committed by Ian Lynagh
parent 5fea49a3c9
commit 18812c810c
6 changed files with 96 additions and 21 deletions

View File

@@ -2811,6 +2811,8 @@ open class KotlinFileExtractor(
return callId
}
val idPropertyRef = tw.getFreshIdLabel<DbPropertyref>()
if (getter != null) {
val getterParameterTypes = parameters.map { it.type }
val getLabels = addFunctionManual(tw.getFreshIdLabel(), "get", getterParameterTypes, getter.owner.returnType, classId, locId)
@@ -2820,6 +2822,8 @@ open class KotlinFileExtractor(
getter,
{ r, c -> extractAccessToTarget(getLabels.methodId, r, c) }
)
tw.writePropertyRefGetBinding(idPropertyRef, getLabels.methodId)
}
if (setter != null) {
@@ -2831,27 +2835,24 @@ open class KotlinFileExtractor(
setter,
{ r, c -> extractAccessToTarget(setLabels.methodId, r, c) }
)
tw.writePropertyRefSetBinding(idPropertyRef, setLabels.methodId)
}
// todo: property ref
// Add constructor (property ref) call:
val exprParent = parent.expr(propertyReferenceExpr, callable)
val idCtorRef = tw.getFreshIdLabel<DbNewexpr>()
tw.writeExprs_newexpr(idCtorRef, ids.type.javaResult.id, exprParent.parent, exprParent.idx)
tw.writeExprsKotlinType(idCtorRef, ids.type.kotlinResult.id)
tw.writeHasLocation(idCtorRef, locId)
tw.writeCallableEnclosingExpr(idCtorRef, callable)
tw.writeStatementEnclosingExpr(idCtorRef, exprParent.enclosingStmt)
tw.writeCallableBinding(idCtorRef, ids.constructor)
tw.writeExprs_propertyref(idPropertyRef, ids.type.javaResult.id, exprParent.parent, exprParent.idx)
tw.writeExprsKotlinType(idPropertyRef, ids.type.kotlinResult.id)
tw.writeHasLocation(idPropertyRef, locId)
tw.writeCallableEnclosingExpr(idPropertyRef, callable)
tw.writeStatementEnclosingExpr(idPropertyRef, exprParent.enclosingStmt)
tw.writeCallableBinding(idPropertyRef, ids.constructor)
extractTypeAccess(kPropertyType, locId, callable, idCtorRef, -3, exprParent.enclosingStmt)
extractTypeAccess(kPropertyType, locId, callable, idPropertyRef, -3, exprParent.enclosingStmt)
// todo: property ref:
//tw.writeMemberRefBinding(idMemberRef, targetCallableId)
helper.extractConstructorArguments(callable, idPropertyRef, exprParent.enclosingStmt)
helper.extractConstructorArguments(callable, idCtorRef, exprParent.enclosingStmt)
tw.writeIsAnonymClass(classId, idCtorRef)
tw.writeIsAnonymClass(classId, idPropertyRef)
}
}

View File

@@ -749,6 +749,7 @@ case @expr.kind of
| 85 = @unsafecoerceexpr
| 86 = @valueeqexpr
| 87 = @valueneexpr
| 88 = @propertyref
;
/** Holds if this `when` expression was written as an `if` expression. */
@@ -764,7 +765,7 @@ when_branch(
/** Holds if this `when` branch was written as an `else` branch. */
when_branch_else(unique int id: @whenbranch ref);
@classinstancexpr = @newexpr | @lambdaexpr | @memberref
@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref
@annotation = @declannotation | @typeannotation
@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess
@@ -845,6 +846,16 @@ memberRefBinding(
int callable: @callable ref
);
propertyRefGetBinding(
unique int id: @expr ref,
int getter: @callable ref
);
propertyRefSetBinding(
unique int id: @expr ref,
int setter: @callable ref
);
@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable;
variableBinding(

View File

@@ -1438,6 +1438,42 @@ class MemberRefExpr extends FunctionalExpr, @memberref {
override string getAPrimaryQlClass() { result = "MemberRefExpr" }
}
/**
* Property references are represented by their implicit class instance expressions,
* which instantiate an anonymous class that overrides the `get` and `set` methods designated by
* their functional interface type.
*/
class PropertyRefExpr extends ClassInstanceExpr, @propertyref {
/**
* Gets the implicit `get` method corresponding to this property reference expression, if any.
*/
Method asGetMethod() {
result = this.getAnonymousClass().getAMethod() and result.getName() = "get"
}
/**
* Gets the implicit `set` method corresponding to this property reference expression, if any.
*/
Method asSetMethod() {
result = this.getAnonymousClass().getAMethod() and result.getName() = "set"
}
/**
* Gets the property getter referenced by this property reference expression, if any.
*/
Callable getGetterCallable() { propertyRefGetBinding(this, result) }
/**
* Gets the property setter referenced by this property reference expression, if any.
*/
Callable getSetterCallable() { propertyRefSetBinding(this, result) }
/** Gets a printable representation of this expression. */
override string toString() { result = "...::..." }
override string getAPrimaryQlClass() { result = "PropertyRefExpr" }
}
/** A conditional expression or a `switch` expression. */
class ChooseExpr extends Expr {
ChooseExpr() { this instanceof ConditionalExpr or this instanceof SwitchExpr }

View File

@@ -18,7 +18,7 @@ reflection.kt:
# 48| 0: [MethodAccess] println(...)
# 48| -1: [TypeAccess] ConsoleKt
# 48| 0: [MethodAccess] get(...)
# 48| -1: [ClassInstanceExpr] new (...)
# 48| -1: [PropertyRefExpr] ...::...
# 48| -4: [AnonymousClass] new KProperty1<String,Character>(...) { ... }
# 48| 1: [Constructor]
# 48| 5: [BlockStmt] { ... }
@@ -36,7 +36,7 @@ reflection.kt:
# 49| 0: [MethodAccess] println(...)
# 49| -1: [TypeAccess] ConsoleKt
# 49| 0: [MethodAccess] get(...)
# 49| -1: [ClassInstanceExpr] new (...)
# 49| -1: [PropertyRefExpr] ...::...
# 49| -4: [AnonymousClass] new KProperty0<Character>(...) { ... }
# 49| 1: [Constructor]
#-----| 4: (Parameters)
@@ -90,7 +90,7 @@ reflection.kt:
# 6| -1: [VarAccess] ref
# 8| 2: [LocalVariableDeclStmt] var ...;
# 8| 1: [LocalVariableDeclExpr] x0
# 8| 0: [ClassInstanceExpr] new (...)
# 8| 0: [PropertyRefExpr] ...::...
# 8| -4: [AnonymousClass] new KProperty1<C,Integer>(...) { ... }
# 8| 1: [Constructor]
# 8| 5: [BlockStmt] { ... }
@@ -146,7 +146,7 @@ reflection.kt:
# 12| 0: [VarAccess] x0
# 13| 7: [LocalVariableDeclStmt] var ...;
# 13| 1: [LocalVariableDeclExpr] x5
# 13| 0: [ClassInstanceExpr] new (...)
# 13| 0: [PropertyRefExpr] ...::...
# 13| -4: [AnonymousClass] new KProperty0<Integer>(...) { ... }
# 13| 1: [Constructor]
#-----| 4: (Parameters)
@@ -171,7 +171,7 @@ reflection.kt:
# 13| -3: [TypeAccess] C
# 15| 8: [LocalVariableDeclStmt] var ...;
# 15| 1: [LocalVariableDeclExpr] y0
# 15| 0: [ClassInstanceExpr] new (...)
# 15| 0: [PropertyRefExpr] ...::...
# 15| -4: [AnonymousClass] new KMutableProperty1<C,Integer>(...) { ... }
# 15| 1: [Constructor]
# 15| 5: [BlockStmt] { ... }
@@ -239,7 +239,7 @@ reflection.kt:
# 19| 0: [VarAccess] y0
# 20| 13: [LocalVariableDeclStmt] var ...;
# 20| 1: [LocalVariableDeclExpr] y5
# 20| 0: [ClassInstanceExpr] new (...)
# 20| 0: [PropertyRefExpr] ...::...
# 20| -4: [AnonymousClass] new KMutableProperty0<Integer>(...) { ... }
# 20| 1: [Constructor]
#-----| 4: (Parameters)

View File

@@ -34,3 +34,15 @@ invocation
| reflection.kt:23:23:23:33 | get(...) | file://<external>/KProperty2.class:0:0:0:0 | get |
| reflection.kt:48:30:48:39 | get(...) | file://<external>/KProperty1.class:0:0:0:0 | get |
| reflection.kt:49:30:49:34 | get(...) | file://<external>/KProperty0.class:0:0:0:0 | get |
functionReferences
| reflection.kt:5:49:5:54 | ...::... | reflection.kt:5:49:5:54 | invoke | reflection.kt:27:9:27:33 | m |
propertyGetReferences
| reflection.kt:8:38:8:42 | ...::... | reflection.kt:8:38:8:42 | get | reflection.kt:8:38:8:42 | get |
| reflection.kt:13:35:13:41 | ...::... | reflection.kt:13:35:13:41 | get | reflection.kt:13:35:13:41 | get |
| reflection.kt:15:45:15:49 | ...::... | reflection.kt:15:45:15:49 | get | reflection.kt:15:45:15:49 | get |
| reflection.kt:20:42:20:48 | ...::... | reflection.kt:20:42:20:48 | get | reflection.kt:20:42:20:48 | get |
| reflection.kt:48:13:48:28 | ...::... | reflection.kt:48:13:48:28 | get | reflection.kt:48:13:48:28 | get |
| reflection.kt:49:13:49:28 | ...::... | reflection.kt:49:13:49:28 | get | reflection.kt:49:13:49:28 | get |
propertySetReferences
| reflection.kt:15:45:15:49 | ...::... | reflection.kt:15:45:15:49 | set | reflection.kt:15:45:15:49 | set |
| reflection.kt:20:42:20:48 | ...::... | reflection.kt:20:42:20:48 | set | reflection.kt:20:42:20:48 | set |

View File

@@ -39,3 +39,18 @@ query predicate variableInitializerType(
query predicate invocation(Call c, Callable callee) {
c.getCallee() = callee and callee.getDeclaringType().getPackage().getName() = "kotlin.reflect"
}
query predicate functionReferences(MemberRefExpr e, Method m, Callable c) {
e.asMethod() = m and
e.getReferencedCallable() = c
}
query predicate propertyGetReferences(PropertyRefExpr e, Method m, Callable c) {
e.asGetMethod() = m and
e.getGetterCallable() = c
}
query predicate propertySetReferences(PropertyRefExpr e, Method m, Callable c) {
e.asSetMethod() = m and
e.getSetterCallable() = c
}