Skip to content

Commit deee3c2

Browse files
authored
fix: initial types that can hold any value should be top (#101)
1 parent 622f8ee commit deee3c2

File tree

4 files changed

+78
-15
lines changed

4 files changed

+78
-15
lines changed

src/main/kotlin/de/sirywell/handlehints/dfa/SsaAnalyzer.kt

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
4343
if (isUnrelated(instruction.variable)) return
4444
val element = controlFlow.getElement(index)
4545
if (element is PsiReferenceExpression && isUnstableVariable(element, instruction.variable)) {
46-
typeData[element] = bottomForType(instruction.variable.type, instruction.variable)
46+
typeData[element] = topForType(instruction.variable.type, instruction.variable)
4747
return
4848
}
4949
val value = ssaConstruction.readVariable(instruction.variable, block)
@@ -217,9 +217,9 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
217217
"parameterList",
218218
"parameterType",
219219
"toMethodDescriptorString",
220-
-> noMethodHandle()
220+
-> unrelatedType()
221221

222-
in objectMethods -> noMethodHandle()
222+
in objectMethods -> unrelatedType()
223223
else -> warnUnsupported(expression, "MethodType")
224224
}
225225
} else if (receiverIsMethodHandles(expression)) {
@@ -245,21 +245,27 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
245245
"describeConstable",
246246
"invoke",
247247
"invokeExact",
248-
"invokeWithArguments" -> noMethodHandle()
248+
"invokeWithArguments" -> unrelatedType()
249249

250250
"type" -> qualifier?.methodHandleType(block)
251251
?.withVarargs(TriState.NO) // if ever used somewhere else, assume non-varargs
252252

253-
in objectMethods -> noMethodHandle()
253+
in objectMethods -> unrelatedType()
254254
else -> warnUnsupported(expression, "MethodHandle")
255255
}
256256
} else if (receiverIsLookup(expression)) {
257257
return lookup(expression, arguments, block)
258+
} else {
259+
return methodExpression.type?.let { topForType(it, expression) }
258260
}
259261
} else if (expression is PsiReferenceExpression) {
260262
val variable = expression.resolve() as? PsiVariable ?: return noMatch()
261263
if (isUnstableVariable(expression, variable)) {
262-
return bottomForType(variable.type, variable)
264+
return topForType(variable.type, variable)
265+
}
266+
// parameters are always top - could be anything
267+
if (variable is PsiParameter) {
268+
return topForType(variable.type, variable)
263269
}
264270
val value = ssaConstruction.readVariable(variable, block)
265271
return if (value is Holder) {
@@ -337,9 +343,9 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
337343
"unreflectSetter",
338344
"unreflectSpecial",
339345
"unreflectVarHandle"
340-
-> noMethodHandle()
346+
-> unrelatedType()
341347

342-
in objectMethods -> noMethodHandle()
348+
in objectMethods -> unrelatedType()
343349
else -> warnUnsupported(expression, "MethodHandles.Lookup")
344350
}
345351
}
@@ -353,7 +359,7 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
353359
return resolver(refc, type)
354360
}
355361

356-
private fun noMethodHandle(): MethodHandleType? = null
362+
private fun unrelatedType(): TypeLatticeElement<*>? = null
357363

358364
private fun methodHandles(
359365
expression: PsiMethodCallExpression,
@@ -551,9 +557,9 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
551557
"lookup",
552558
"privateLookupIn",
553559
"publicLookup",
554-
"reflectAs" -> noMethodHandle()
560+
"reflectAs" -> unrelatedType()
555561

556-
in objectMethods -> noMethodHandle()
562+
in objectMethods -> unrelatedType()
557563
else -> warnUnsupported(expression, "MethodHandles")
558564
}
559565
}
@@ -563,7 +569,7 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
563569
}
564570

565571
private inline fun <reified T : TypeLatticeElement<T>> notConstant(): T {
566-
return bottomForType<T>()
572+
return topForType<T>()
567573
}
568574

569575
private fun singleParameter(
@@ -642,4 +648,30 @@ class SsaAnalyzer(private val controlFlow: ControlFlow, val typeData: TypeData)
642648
}
643649
}
644650

651+
private inline fun <reified T : TypeLatticeElement<*>> topForType(): T {
652+
return topForType(T::class)
653+
}
654+
655+
private fun <T : TypeLatticeElement<*>> topForType(clazz: KClass<T>): T {
656+
if (clazz == MethodHandleType::class) {
657+
return clazz.java.cast(TopMethodHandleType)
658+
}
659+
if (clazz == VarHandleType::class) {
660+
return clazz.java.cast(TopVarHandleType)
661+
}
662+
if (clazz == Type::class) {
663+
return clazz.java.cast(TopType)
664+
}
665+
throw UnsupportedOperationException("$clazz is not supported")
666+
}
667+
668+
private fun topForType(psiType: PsiType, context: PsiElement): TypeLatticeElement<*> {
669+
return when (psiType) {
670+
methodTypeType(context) -> topForType<MethodHandleType>()
671+
methodHandleType(context) -> topForType<MethodHandleType>()
672+
varHandleType(context) -> topForType<VarHandleType>()
673+
else -> throw UnsupportedOperationException("${psiType.presentableText} is not supported")
674+
}
675+
}
676+
645677
}

src/test/kotlin/de/sirywell/handlehints/mhtype/MethodHandleInspectionsTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class MethodHandleInspectionsTest : LightJavaCodeInsightFixtureTestCase() {
3737

3838
fun testFinalFields() = doTypeCheckingTest()
3939

40+
fun testInitialTypes() = doTypeCheckingTest()
41+
4042
fun testLookupFindConstructor() = doTypeCheckingTest()
4143

4244
fun testLookupFindGetter() = doTypeCheckingTest()

src/test/testData/FinalFields.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ public class FinalFields {
2727
<info descr="(CharSequence)int">this.methodType = <info descr="(CharSequence)int">MethodType.methodType(int.class, CharSequence.class)</info></info>;
2828
<info descr="(CharSequence)int">MethodHandle mn = <info descr="(CharSequence)int">MethodHandles.empty(this.methodType)</info>;</info>
2929
<info descr="(CharSequence)int">MethodHandle mni = <info descr="(CharSequence)int">MethodHandles.empty(methodType)</info>;</info>
30-
<info descr="BotMethodHandleType">MethodHandle o = <info descr="BotMethodHandleType">MethodHandles.empty(other.methodType)</info>;</info>
30+
<info descr="TopMethodHandleType">MethodHandle o = <info descr="TopMethodHandleType">MethodHandles.empty(other.methodType)</info>;</info>
3131
if (Math.random() < 0.5) {
3232
other = this;
33-
<info descr="BotMethodHandleType">MethodHandle oy = <info descr="BotMethodHandleType">MethodHandles.empty(other.methodType)</info>;</info>
33+
<info descr="TopMethodHandleType">MethodHandle oy = <info descr="TopMethodHandleType">MethodHandles.empty(other.methodType)</info>;</info>
3434
}
35-
<info descr="BotMethodHandleType">MethodHandle om = <info descr="BotMethodHandleType">MethodHandles.empty(other.methodType)</info>;</info>
35+
<info descr="TopMethodHandleType">MethodHandle om = <info descr="TopMethodHandleType">MethodHandles.empty(other.methodType)</info>;</info>
3636
}
3737

3838
void m() {

src/test/testData/InitialTypes.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import java.lang.invoke.MethodHandle;
2+
import java.lang.invoke.MethodHandles;
3+
import java.lang.invoke.MethodType;
4+
5+
public class InitialTypes {
6+
7+
void m(MethodType mt, boolean b, Inner inner) {
8+
MethodHandle mh0;
9+
if (b) {
10+
<info descr="TopMethodHandleType">mh0 = <info descr="TopMethodHandleType">MethodHandles.empty(mt)</info></info>;
11+
} else {
12+
<info descr="()int">mh0 = <info descr="()int">MethodHandles.zero(int.class)</info></info>;
13+
}
14+
<info descr="TopMethodHandleType">MethodHandle mh1 = <info descr="TopMethodHandleType">myMethodHandleMethod()</info>;</info>
15+
<info descr="TopMethodHandleType">MethodHandle mh2 = inner.methodHandle;</info>
16+
<info descr="TopMethodHandleType">MethodHandle mh3 = create().methodHandle;</info>
17+
}
18+
19+
private MethodHandle myMethodHandleMethod() {
20+
return MethodHandles.zero(Object.class);
21+
}
22+
23+
private Inner create() {
24+
return new Inner();
25+
}
26+
static class Inner {
27+
MethodHandle methodHandle;
28+
}
29+
}

0 commit comments

Comments
 (0)