Skip to content

Commit

Permalink
feature: support VarHandle-producing methods from MH.Lookup (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
SirYwell committed Jun 23, 2024
1 parent 4c2a3b5 commit ccb94ad
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 7 deletions.
14 changes: 7 additions & 7 deletions src/main/kotlin/de/sirywell/handlehints/dfa/SsaAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
expression: PsiMethodCallExpression,
arguments: List<PsiExpression>,
block: Block
): MethodHandleType? {
): TypeLatticeElement<*>? {
return when (expression.methodName) {
"findConstructor" -> {
if (arguments.size != 2) return noMatch()
Expand Down Expand Up @@ -281,6 +281,8 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
val t = type.methodHandleType(block) ?: return notConstant()
lookupHelper.findVirtual(refc, name, t)
}
"findStaticVarHandle" -> findAccessor(arguments, lookupHelper::findStaticVarHandle)
"findVarHandle" -> findAccessor(arguments, lookupHelper::findVarHandle)

"accessClass",
"defineClass",
Expand All @@ -289,8 +291,6 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
"dropLookupMode",
"ensureInitialized",
"findClass",
"findStaticVarHandle",
"findVarHandle",
"hasFullPrivilegeAccess",
"hasPrivateAccess",
"in",
Expand All @@ -310,10 +310,10 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
}
}

private fun findAccessor(
private fun <T> findAccessor(
arguments: List<PsiExpression>,
resolver: (PsiExpression, PsiExpression) -> MethodHandleType
): MethodHandleType? {
resolver: (PsiExpression, PsiExpression) -> T
): T? {
if (arguments.size != 3) return noMatch()
val (refc, _, type) = arguments
return resolver(refc, type)
Expand Down Expand Up @@ -524,7 +524,7 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
}
}

private fun noMatch(): MethodHandleType? {
private fun <T: TypeLatticeElement<*>> noMatch(): T? {
return null
}

Expand Down
12 changes: 12 additions & 0 deletions src/main/kotlin/de/sirywell/handlehints/mhtype/LookupHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,16 @@ class LookupHelper(private val ssaAnalyzer: SsaAnalyzer) : ProblemEmitter(ssaAna
}
return MethodHandleType(signature)
}

fun findStaticVarHandle(declExpr: PsiExpression, typeExpr: PsiExpression): VarHandleType {
declExpr.asReferenceType() // problem reporting only, not needed otherwise
val type = typeExpr.asNonVoidType()
return CompleteVarHandleType(type, CompleteParameterList(listOf()))
}

fun findVarHandle(recvExpr: PsiExpression, typeExpr: PsiExpression): VarHandleType {
val recv = recvExpr.asReferenceType()
val type = typeExpr.asNonVoidType()
return CompleteVarHandleType(type, CompleteParameterList(listOf(recv)))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ class MethodHandleInspectionsTest : LightJavaCodeInsightFixtureTestCase() {

fun testLookupFindStaticSetter() = doTypeCheckingTest()

fun testLookupFindStaticVarHandle() = doTypeCheckingTest()

fun testLookupFindVarHandle() = doTypeCheckingTest()

fun testLookupFindVirtual() = doTypeCheckingTest()

fun testMethodHandlesArrayConstructor() = doTypeCheckingTest()
Expand Down
19 changes: 19 additions & 0 deletions src/test/testData/LookupFindStaticVarHandle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;

class LookupFindStaticVarHandle {
static {
try {
// valid
<info descr="()(Boolean)">VarHandle vh0 = <info descr="()(Boolean)">MethodHandles.lookup().findStaticVarHandle(Boolean.class, "FALSE", Boolean.class)</info>;</info>
// invalid - field cannot be of type void
<info descr="()(⊤)">VarHandle vh1 = <info descr="()(⊤)">MethodHandles.lookup().findStaticVarHandle(Boolean.class, "FALSE", void.class)</info>;</info>
// invalid - target class cannot be void
<info descr="()(Boolean)">VarHandle vh2 = <info descr="()(Boolean)">MethodHandles.lookup().findStaticVarHandle(void.class, "FALSE", Boolean.class)</info>;</info>
// invalid - target class cannot be int
<info descr="()(Boolean)">VarHandle vh3 = <info descr="()(Boolean)">MethodHandles.lookup().findStaticVarHandle(int.class, "FALSE", Boolean.class)</info>;</info>
} catch (Throwable ignored) {}
}
}
20 changes: 20 additions & 0 deletions src/test/testData/LookupFindVarHandle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;

class LookupFindVarHandle {
int myField;
static {
try {
// valid
<info descr="(LookupFindVarHandle)(int)">VarHandle vh0 = <info descr="(LookupFindVarHandle)(int)">MethodHandles.lookup().findVarHandle(LookupFindVarHandle.class, "myField", int.class)</info>;</info>
// invalid - field cannot be of type void
<info descr="(LookupFindVarHandle)(⊤)">VarHandle vh1 = <info descr="(LookupFindVarHandle)(⊤)">MethodHandles.lookup().findVarHandle(LookupFindVarHandle.class, "myField", void.class)</info>;</info>
// invalid - target class cannot be void
<info descr="(⊤)(int)">VarHandle vh2 = <info descr="(⊤)(int)">MethodHandles.lookup().findVarHandle(void.class, "myField", int.class)</info>;</info>
// invalid - target class cannot be int
<info descr="(⊤)(int)">VarHandle vh3 = <info descr="(⊤)(int)">MethodHandles.lookup().findVarHandle(int.class, "myField", int.class)</info>;</info>
} catch (Throwable ignored) {}
}
}

0 comments on commit ccb94ad

Please sign in to comment.