User: joe Date: 22 Jun 25 19:56 Revision: c554289dcc7771bd0d959c80e462714b966fb4f4 Summary: Cherry pick fixes from lambda desugarer that we can use now TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=10078&personal=false Index: src/main/kotlin/platform/mixin/handlers/desugar/DesugarContext.kt =================================================================== --- src/main/kotlin/platform/mixin/handlers/desugar/DesugarContext.kt (revision 3ef92c6f6e75c20372c9ca2890716b3295452a2a) +++ src/main/kotlin/platform/mixin/handlers/desugar/DesugarContext.kt (revision c554289dcc7771bd0d959c80e462714b966fb4f4) @@ -20,4 +20,4 @@ package com.demonwav.mcdev.platform.mixin.handlers.desugar -class DesugarContext(val classVersion: Int) +data class DesugarContext(val classVersion: Int) Index: src/main/kotlin/platform/mixin/handlers/desugar/DesugarUtil.kt =================================================================== --- src/main/kotlin/platform/mixin/handlers/desugar/DesugarUtil.kt (revision 3ef92c6f6e75c20372c9ca2890716b3295452a2a) +++ src/main/kotlin/platform/mixin/handlers/desugar/DesugarUtil.kt (revision c554289dcc7771bd0d959c80e462714b966fb4f4) @@ -22,6 +22,8 @@ import com.demonwav.mcdev.util.cached import com.demonwav.mcdev.util.childrenOfType +import com.demonwav.mcdev.util.findContainingClass +import com.demonwav.mcdev.util.packageName import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key import com.intellij.openapi.util.TextRange @@ -30,25 +32,31 @@ import com.intellij.psi.PsiAnonymousClass import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement +import com.intellij.psi.PsiJavaCodeReferenceElement import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiLambdaExpression import com.intellij.psi.PsiMember import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodReferenceExpression +import com.intellij.psi.PsiModifier import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.PsiReference import com.intellij.psi.PsiSubstitutor +import com.intellij.psi.PsiSuperExpression import com.intellij.psi.PsiTypeParameter import com.intellij.psi.PsiVariable import com.intellij.psi.impl.light.LightMemberReference import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.PsiUtil import com.intellij.psi.util.parents import com.intellij.refactoring.util.LambdaRefactoringUtil import com.intellij.util.JavaPsiConstructorUtil import com.intellij.util.Processor import org.jetbrains.annotations.VisibleForTesting +import org.objectweb.asm.Opcodes object DesugarUtil { private val ORIGINAL_ELEMENT_KEY = Key.create("mcdev.desugar.originalElement") @@ -210,4 +218,36 @@ } return lambda } + + // see com.sun.tools.javac.comp.Lower.access, accReq + fun needsBridgeMethod(expression: PsiJavaCodeReferenceElement, classVersion: Int): Boolean { + // method calls with qualified super need bridge methods + if (expression is PsiMethodCallExpression) { + val qualifier = PsiUtil.skipParenthesizedExprDown(expression.methodExpression.qualifierExpression) + if (qualifier is PsiSuperExpression && qualifier.qualifier != null) { + return true -} + } + } + + val resolved = expression.resolve() as? PsiMember ?: return false + val resolvedClass = resolved.containingClass ?: return false + val fromClass = expression.findContainingClass() ?: return false + + if (resolvedClass == fromClass) { + return false + } + + if (classVersion <= Opcodes.V1_8 && resolved.hasModifierProperty(PsiModifier.PRIVATE)) { + return true + } + + if (resolved.hasModifierProperty(PsiModifier.PROTECTED) && + fromClass.packageName != resolvedClass.packageName && + !fromClass.isInheritor(resolvedClass, true) + ) { + return true + } + + return false + } +} Index: src/main/kotlin/platform/mixin/util/AsmUtil.kt =================================================================== --- src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision 3ef92c6f6e75c20372c9ca2890716b3295452a2a) +++ src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision c554289dcc7771bd0d959c80e462714b966fb4f4) @@ -782,7 +782,7 @@ // walk inside the reference first, visits the qualifier first (it's first in the bytecode) super.visitMethodReferenceExpression(expression) - if (expression.hasSyntheticMethod) { + if (expression.hasSyntheticMethod(clazz.version)) { if (matcher.accept(expression)) { stopWalking() } Index: src/main/kotlin/util/bytecode-utils.kt =================================================================== --- src/main/kotlin/util/bytecode-utils.kt (revision 3ef92c6f6e75c20372c9ca2890716b3295452a2a) +++ src/main/kotlin/util/bytecode-utils.kt (revision c554289dcc7771bd0d959c80e462714b966fb4f4) @@ -25,12 +25,15 @@ import com.intellij.psi.PsiArrayType import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassType +import com.intellij.psi.PsiDisjunctionType import com.intellij.psi.PsiField +import com.intellij.psi.PsiIntersectionType import com.intellij.psi.PsiMethod import com.intellij.psi.PsiModifier import com.intellij.psi.PsiPrimitiveType import com.intellij.psi.PsiType import com.intellij.psi.PsiTypes +import com.intellij.psi.PsiWildcardType import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.TypeConversionUtil import org.jetbrains.plugins.groovy.lang.resolve.processors.inference.type @@ -91,6 +94,9 @@ is PsiPrimitiveType -> builder.append(internalName) is PsiArrayType -> componentType.appendDescriptor(builder.append('[')) is PsiClassType -> appendInternalName(builder.append('L')).append(';') + is PsiWildcardType -> extendsBound.appendDescriptor(builder) + is PsiIntersectionType -> conjuncts.first().appendDescriptor(builder) + is PsiDisjunctionType -> leastUpperBound.appendDescriptor(builder) else -> throw IllegalArgumentException("Unsupported PsiType: $this") } } Index: src/main/kotlin/util/psi-utils.kt =================================================================== --- src/main/kotlin/util/psi-utils.kt (revision 3ef92c6f6e75c20372c9ca2890716b3295452a2a) +++ src/main/kotlin/util/psi-utils.kt (revision c554289dcc7771bd0d959c80e462714b966fb4f4) @@ -23,6 +23,7 @@ import com.demonwav.mcdev.facet.MinecraftFacet import com.demonwav.mcdev.platform.mcp.McpModule import com.demonwav.mcdev.platform.mcp.McpModuleType +import com.demonwav.mcdev.platform.mixin.handlers.desugar.DesugarUtil import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.debugger.impl.DebuggerUtilsEx import com.intellij.ide.highlighter.JavaClassFileType @@ -42,9 +43,13 @@ import com.intellij.psi.ElementManipulator import com.intellij.psi.ElementManipulators import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.LambdaUtil import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiArrayType import com.intellij.psi.PsiClass +import com.intellij.psi.PsiClassType import com.intellij.psi.PsiDirectory +import com.intellij.psi.PsiDisjunctionType import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementFactory @@ -52,6 +57,7 @@ import com.intellij.psi.PsiEllipsisType import com.intellij.psi.PsiExpression import com.intellij.psi.PsiFile +import com.intellij.psi.PsiIntersectionType import com.intellij.psi.PsiKeyword import com.intellij.psi.PsiLanguageInjectionHost import com.intellij.psi.PsiManager @@ -67,7 +73,10 @@ import com.intellij.psi.PsiPrimitiveType import com.intellij.psi.PsiReference import com.intellij.psi.PsiReferenceExpression +import com.intellij.psi.PsiSuperExpression import com.intellij.psi.PsiType +import com.intellij.psi.PsiTypeElement +import com.intellij.psi.PsiTypeParameter import com.intellij.psi.ResolveResult import com.intellij.psi.filters.ElementFilter import com.intellij.psi.search.GlobalSearchScope @@ -76,6 +85,7 @@ import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTypesUtil +import com.intellij.psi.util.PsiUtil import com.intellij.psi.util.TypeConversionUtil import com.intellij.psi.util.parentOfType import com.intellij.refactoring.changeSignature.ChangeSignatureUtil @@ -371,22 +381,105 @@ } } -@Suppress("PrivatePropertyName") private val REAL_NAME_KEY = Key("mcdev.real_name") var PsiMember.realName: String? get() = getUserData(REAL_NAME_KEY) set(value) = putUserData(REAL_NAME_KEY, value) -val PsiMethodReferenceExpression.hasSyntheticMethod: Boolean +// see com.sun.tools.javac.comp.TransTypes.needsConversionToLambda +fun PsiMethodReferenceExpression.hasSyntheticMethod(classVersion: Int): Boolean { + val qualifier = this.qualifier ?: return true + + if (qualifier is PsiTypeElement && qualifier.type is PsiArrayType) { + return true + } + + if (qualifier is PsiSuperExpression) { + return true + } + + val referencedClass = when (qualifier) { + is PsiTypeElement -> (qualifier.type as? PsiClassType)?.resolve() + is PsiReferenceExpression -> qualifier.resolve() as? PsiClass + else -> null + } + + if (isConstructor) { + if (referencedClass?.containingClass != null && !referencedClass.hasModifierProperty(PsiModifier.STATIC)) { + return true + } + if (referencedClass != null && PsiUtil.isLocalOrAnonymousClass(referencedClass)) { + return true + } + } + + if (isVarArgsCall) { + return true + } + + if (DesugarUtil.needsBridgeMethod(this, classVersion)) { + return true + } + + // even if a bridge method isn't required, if the method is protected in a different package, a synthetic method is + // still required, because otherwise the synthetic class that LambdaMetafactory creates won't be able to access it + val resolved = resolve() ?: return true + when (resolved) { + is PsiClass -> return !isConstructor + !is PsiMethod -> return true + } + if (resolved.hasModifierProperty(PsiModifier.PROTECTED) && findContainingClass()?.packageName != referencedClass?.packageName) { + return true + } + + val functionalInterfaceType = this.functionalInterfaceType ?: return true + val interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) ?: return true + + return interfaceMethod.parameterList.parameters.any { param -> + var paramType = param.type + while (paramType is PsiClassType) { + val resolved = paramType.resolve() + if (resolved is PsiTypeParameter) { + val extendsList = resolved.extendsList.referencedTypes + when (extendsList.size) { + 0 -> break + 1 -> paramType = extendsList.single() + else -> return@any true + } + } + } + paramType is PsiIntersectionType || paramType is PsiDisjunctionType + } +} + +private val PsiMethodReferenceExpression.isVarArgsCall: Boolean get() { - // the only method reference that doesn't have a synthetic method is a direct reference to a method - if (referenceName == "new") return true - val qualifier = this.qualifier - if (qualifier !is PsiReferenceExpression) return true - return qualifier.resolve() !is PsiClass + val resolveResult = advancedResolve(false) + val resolvedMethod = resolveResult.element as? PsiMethod ?: return false + if (!resolvedMethod.isVarArgs) { + return false - } + } + val functionalInterfaceType = this.functionalInterfaceType ?: return true + val functionalResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType) + val interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalResolveResult) ?: return true + + val interfaceSignature = interfaceMethod.getSignature(LambdaUtil.getSubstitutor(interfaceMethod, functionalResolveResult)) + val interfaceParamTypes = interfaceSignature.parameterTypes + + val resolvedParams = resolvedMethod.parameterList.parameters + val isStatic = resolvedMethod.hasModifierProperty(PsiModifier.STATIC) + val effectiveNumParams = if (isStatic) resolvedParams.size else resolvedParams.size + 1 + if (effectiveNumParams != interfaceParamTypes.size) { + return true + } + + val varArgsType = resolvedParams.lastOrNull()?.type as? PsiEllipsisType ?: return true + val arrayType = resolveResult.substitutor.substitute(varArgsType.toArrayType()) + return !arrayType.isAssignableFrom(interfaceParamTypes.last()) + } + val PsiClass.psiType: PsiType get() = PsiTypesUtil.getClassType(this)