Skip to content

Commit c554289

Browse files
committed
Cherry pick fixes from lambda desugarer that we can use now
1 parent 3ef92c6 commit c554289

File tree

5 files changed

+148
-9
lines changed

5 files changed

+148
-9
lines changed

src/main/kotlin/platform/mixin/handlers/desugar/DesugarContext.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@
2020

2121
package com.demonwav.mcdev.platform.mixin.handlers.desugar
2222

23-
class DesugarContext(val classVersion: Int)
23+
data class DesugarContext(val classVersion: Int)

src/main/kotlin/platform/mixin/handlers/desugar/DesugarUtil.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ package com.demonwav.mcdev.platform.mixin.handlers.desugar
2222

2323
import com.demonwav.mcdev.util.cached
2424
import com.demonwav.mcdev.util.childrenOfType
25+
import com.demonwav.mcdev.util.findContainingClass
26+
import com.demonwav.mcdev.util.packageName
2527
import com.intellij.openapi.project.Project
2628
import com.intellij.openapi.util.Key
2729
import com.intellij.openapi.util.TextRange
@@ -30,25 +32,31 @@ import com.intellij.psi.JavaRecursiveElementWalkingVisitor
3032
import com.intellij.psi.PsiAnonymousClass
3133
import com.intellij.psi.PsiClass
3234
import com.intellij.psi.PsiElement
35+
import com.intellij.psi.PsiJavaCodeReferenceElement
3336
import com.intellij.psi.PsiJavaFile
3437
import com.intellij.psi.PsiLambdaExpression
3538
import com.intellij.psi.PsiMember
3639
import com.intellij.psi.PsiMethod
40+
import com.intellij.psi.PsiMethodCallExpression
3741
import com.intellij.psi.PsiMethodReferenceExpression
42+
import com.intellij.psi.PsiModifier
3843
import com.intellij.psi.PsiNameIdentifierOwner
3944
import com.intellij.psi.PsiReference
4045
import com.intellij.psi.PsiSubstitutor
46+
import com.intellij.psi.PsiSuperExpression
4147
import com.intellij.psi.PsiTypeParameter
4248
import com.intellij.psi.PsiVariable
4349
import com.intellij.psi.impl.light.LightMemberReference
4450
import com.intellij.psi.search.LocalSearchScope
4551
import com.intellij.psi.search.searches.ReferencesSearch
4652
import com.intellij.psi.util.PsiTreeUtil
53+
import com.intellij.psi.util.PsiUtil
4754
import com.intellij.psi.util.parents
4855
import com.intellij.refactoring.util.LambdaRefactoringUtil
4956
import com.intellij.util.JavaPsiConstructorUtil
5057
import com.intellij.util.Processor
5158
import org.jetbrains.annotations.VisibleForTesting
59+
import org.objectweb.asm.Opcodes
5260

5361
object DesugarUtil {
5462
private val ORIGINAL_ELEMENT_KEY = Key.create<PsiElement>("mcdev.desugar.originalElement")
@@ -210,4 +218,36 @@ object DesugarUtil {
210218
}
211219
return lambda
212220
}
221+
222+
// see com.sun.tools.javac.comp.Lower.access, accReq
223+
fun needsBridgeMethod(expression: PsiJavaCodeReferenceElement, classVersion: Int): Boolean {
224+
// method calls with qualified super need bridge methods
225+
if (expression is PsiMethodCallExpression) {
226+
val qualifier = PsiUtil.skipParenthesizedExprDown(expression.methodExpression.qualifierExpression)
227+
if (qualifier is PsiSuperExpression && qualifier.qualifier != null) {
228+
return true
229+
}
230+
}
231+
232+
val resolved = expression.resolve() as? PsiMember ?: return false
233+
val resolvedClass = resolved.containingClass ?: return false
234+
val fromClass = expression.findContainingClass() ?: return false
235+
236+
if (resolvedClass == fromClass) {
237+
return false
238+
}
239+
240+
if (classVersion <= Opcodes.V1_8 && resolved.hasModifierProperty(PsiModifier.PRIVATE)) {
241+
return true
242+
}
243+
244+
if (resolved.hasModifierProperty(PsiModifier.PROTECTED) &&
245+
fromClass.packageName != resolvedClass.packageName &&
246+
!fromClass.isInheritor(resolvedClass, true)
247+
) {
248+
return true
249+
}
250+
251+
return false
252+
}
213253
}

src/main/kotlin/platform/mixin/util/AsmUtil.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ private fun findAssociatedLambda(project: Project, scope: GlobalSearchScope, cla
782782
// walk inside the reference first, visits the qualifier first (it's first in the bytecode)
783783
super.visitMethodReferenceExpression(expression)
784784

785-
if (expression.hasSyntheticMethod) {
785+
if (expression.hasSyntheticMethod(clazz.version)) {
786786
if (matcher.accept(expression)) {
787787
stopWalking()
788788
}

src/main/kotlin/util/bytecode-utils.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ import com.intellij.psi.JavaPsiFacade
2525
import com.intellij.psi.PsiArrayType
2626
import com.intellij.psi.PsiClass
2727
import com.intellij.psi.PsiClassType
28+
import com.intellij.psi.PsiDisjunctionType
2829
import com.intellij.psi.PsiField
30+
import com.intellij.psi.PsiIntersectionType
2931
import com.intellij.psi.PsiMethod
3032
import com.intellij.psi.PsiModifier
3133
import com.intellij.psi.PsiPrimitiveType
3234
import com.intellij.psi.PsiType
3335
import com.intellij.psi.PsiTypes
36+
import com.intellij.psi.PsiWildcardType
3437
import com.intellij.psi.search.GlobalSearchScope
3538
import com.intellij.psi.util.TypeConversionUtil
3639
import org.jetbrains.plugins.groovy.lang.resolve.processors.inference.type
@@ -91,6 +94,9 @@ private fun PsiType.appendDescriptor(builder: StringBuilder): StringBuilder {
9194
is PsiPrimitiveType -> builder.append(internalName)
9295
is PsiArrayType -> componentType.appendDescriptor(builder.append('['))
9396
is PsiClassType -> appendInternalName(builder.append('L')).append(';')
97+
is PsiWildcardType -> extendsBound.appendDescriptor(builder)
98+
is PsiIntersectionType -> conjuncts.first().appendDescriptor(builder)
99+
is PsiDisjunctionType -> leastUpperBound.appendDescriptor(builder)
94100
else -> throw IllegalArgumentException("Unsupported PsiType: $this")
95101
}
96102
}

src/main/kotlin/util/psi-utils.kt

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ package com.demonwav.mcdev.util
2323
import com.demonwav.mcdev.facet.MinecraftFacet
2424
import com.demonwav.mcdev.platform.mcp.McpModule
2525
import com.demonwav.mcdev.platform.mcp.McpModuleType
26+
import com.demonwav.mcdev.platform.mixin.handlers.desugar.DesugarUtil
2627
import com.intellij.codeInsight.lookup.LookupElementBuilder
2728
import com.intellij.debugger.impl.DebuggerUtilsEx
2829
import com.intellij.ide.highlighter.JavaClassFileType
@@ -42,16 +43,21 @@ import com.intellij.openapi.util.text.StringUtil
4243
import com.intellij.psi.ElementManipulator
4344
import com.intellij.psi.ElementManipulators
4445
import com.intellij.psi.JavaPsiFacade
46+
import com.intellij.psi.LambdaUtil
4547
import com.intellij.psi.PsiAnnotation
48+
import com.intellij.psi.PsiArrayType
4649
import com.intellij.psi.PsiClass
50+
import com.intellij.psi.PsiClassType
4751
import com.intellij.psi.PsiDirectory
52+
import com.intellij.psi.PsiDisjunctionType
4853
import com.intellij.psi.PsiDocumentManager
4954
import com.intellij.psi.PsiElement
5055
import com.intellij.psi.PsiElementFactory
5156
import com.intellij.psi.PsiElementResolveResult
5257
import com.intellij.psi.PsiEllipsisType
5358
import com.intellij.psi.PsiExpression
5459
import com.intellij.psi.PsiFile
60+
import com.intellij.psi.PsiIntersectionType
5561
import com.intellij.psi.PsiKeyword
5662
import com.intellij.psi.PsiLanguageInjectionHost
5763
import com.intellij.psi.PsiManager
@@ -67,7 +73,10 @@ import com.intellij.psi.PsiParameterList
6773
import com.intellij.psi.PsiPrimitiveType
6874
import com.intellij.psi.PsiReference
6975
import com.intellij.psi.PsiReferenceExpression
76+
import com.intellij.psi.PsiSuperExpression
7077
import com.intellij.psi.PsiType
78+
import com.intellij.psi.PsiTypeElement
79+
import com.intellij.psi.PsiTypeParameter
7180
import com.intellij.psi.ResolveResult
7281
import com.intellij.psi.filters.ElementFilter
7382
import com.intellij.psi.search.GlobalSearchScope
@@ -76,6 +85,7 @@ import com.intellij.psi.util.CachedValueProvider
7685
import com.intellij.psi.util.CachedValuesManager
7786
import com.intellij.psi.util.PsiTreeUtil
7887
import com.intellij.psi.util.PsiTypesUtil
88+
import com.intellij.psi.util.PsiUtil
7989
import com.intellij.psi.util.TypeConversionUtil
8090
import com.intellij.psi.util.parentOfType
8191
import com.intellij.refactoring.changeSignature.ChangeSignatureUtil
@@ -371,20 +381,103 @@ val PsiElement.mcVersion: SemanticVersion?
371381
}
372382
}
373383

374-
@Suppress("PrivatePropertyName")
375384
private val REAL_NAME_KEY = Key<String>("mcdev.real_name")
376385

377386
var PsiMember.realName: String?
378387
get() = getUserData(REAL_NAME_KEY)
379388
set(value) = putUserData(REAL_NAME_KEY, value)
380389

381-
val PsiMethodReferenceExpression.hasSyntheticMethod: Boolean
390+
// see com.sun.tools.javac.comp.TransTypes.needsConversionToLambda
391+
fun PsiMethodReferenceExpression.hasSyntheticMethod(classVersion: Int): Boolean {
392+
val qualifier = this.qualifier ?: return true
393+
394+
if (qualifier is PsiTypeElement && qualifier.type is PsiArrayType) {
395+
return true
396+
}
397+
398+
if (qualifier is PsiSuperExpression) {
399+
return true
400+
}
401+
402+
val referencedClass = when (qualifier) {
403+
is PsiTypeElement -> (qualifier.type as? PsiClassType)?.resolve()
404+
is PsiReferenceExpression -> qualifier.resolve() as? PsiClass
405+
else -> null
406+
}
407+
408+
if (isConstructor) {
409+
if (referencedClass?.containingClass != null && !referencedClass.hasModifierProperty(PsiModifier.STATIC)) {
410+
return true
411+
}
412+
if (referencedClass != null && PsiUtil.isLocalOrAnonymousClass(referencedClass)) {
413+
return true
414+
}
415+
}
416+
417+
if (isVarArgsCall) {
418+
return true
419+
}
420+
421+
if (DesugarUtil.needsBridgeMethod(this, classVersion)) {
422+
return true
423+
}
424+
425+
// even if a bridge method isn't required, if the method is protected in a different package, a synthetic method is
426+
// still required, because otherwise the synthetic class that LambdaMetafactory creates won't be able to access it
427+
val resolved = resolve() ?: return true
428+
when (resolved) {
429+
is PsiClass -> return !isConstructor
430+
!is PsiMethod -> return true
431+
}
432+
if (resolved.hasModifierProperty(PsiModifier.PROTECTED) && findContainingClass()?.packageName != referencedClass?.packageName) {
433+
return true
434+
}
435+
436+
val functionalInterfaceType = this.functionalInterfaceType ?: return true
437+
val interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) ?: return true
438+
439+
return interfaceMethod.parameterList.parameters.any { param ->
440+
var paramType = param.type
441+
while (paramType is PsiClassType) {
442+
val resolved = paramType.resolve()
443+
if (resolved is PsiTypeParameter) {
444+
val extendsList = resolved.extendsList.referencedTypes
445+
when (extendsList.size) {
446+
0 -> break
447+
1 -> paramType = extendsList.single()
448+
else -> return@any true
449+
}
450+
}
451+
}
452+
paramType is PsiIntersectionType || paramType is PsiDisjunctionType
453+
}
454+
}
455+
456+
private val PsiMethodReferenceExpression.isVarArgsCall: Boolean
382457
get() {
383-
// the only method reference that doesn't have a synthetic method is a direct reference to a method
384-
if (referenceName == "new") return true
385-
val qualifier = this.qualifier
386-
if (qualifier !is PsiReferenceExpression) return true
387-
return qualifier.resolve() !is PsiClass
458+
val resolveResult = advancedResolve(false)
459+
val resolvedMethod = resolveResult.element as? PsiMethod ?: return false
460+
if (!resolvedMethod.isVarArgs) {
461+
return false
462+
}
463+
464+
val functionalInterfaceType = this.functionalInterfaceType ?: return true
465+
val functionalResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType)
466+
val interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalResolveResult) ?: return true
467+
468+
val interfaceSignature = interfaceMethod.getSignature(LambdaUtil.getSubstitutor(interfaceMethod, functionalResolveResult))
469+
val interfaceParamTypes = interfaceSignature.parameterTypes
470+
471+
val resolvedParams = resolvedMethod.parameterList.parameters
472+
val isStatic = resolvedMethod.hasModifierProperty(PsiModifier.STATIC)
473+
val effectiveNumParams = if (isStatic) resolvedParams.size else resolvedParams.size + 1
474+
if (effectiveNumParams != interfaceParamTypes.size) {
475+
return true
476+
}
477+
478+
val varArgsType = resolvedParams.lastOrNull()?.type as? PsiEllipsisType ?: return true
479+
val arrayType = resolveResult.substitutor.substitute(varArgsType.toArrayType())
480+
return !arrayType.isAssignableFrom(interfaceParamTypes.last())
388481
}
389482

390483
val PsiClass.psiType: PsiType

0 commit comments

Comments
 (0)