User: joe Date: 20 Jul 25 11:46 Revision: 62e8d4ceea59f88f7423fd016ff4d04e505d18a6 Summary: Merge branch '2024.3' into 2025.1 # Conflicts: # src/main/kotlin/platform/mixin/util/AsmUtil.kt TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=10112&personal=false Index: build.gradle.kts =================================================================== --- build.gradle.kts (revision 0649022ea7495569c4a54abfea2d1d6df86dc219) +++ build.gradle.kts (revision 62e8d4ceea59f88f7423fd016ff4d04e505d18a6) @@ -90,6 +90,7 @@ exclude(group = "org.ow2.asm", module = "asm-debug-all") } testLibs(libs.mixinExtras.common) + implementation(libs.jgraphx) implementation(libs.mappingIo) implementation(libs.bundles.asm) Index: gradle/libs.versions.toml =================================================================== --- gradle/libs.versions.toml (revision 0649022ea7495569c4a54abfea2d1d6df86dc219) +++ gradle/libs.versions.toml (revision 62e8d4ceea59f88f7423fd016ff4d04e505d18a6) @@ -34,7 +34,8 @@ coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" } mappingIo = "net.fabricmc:mapping-io:0.2.1" -mixinExtras-expressions = "io.github.llamalad7:mixinextras-expressions:0.0.4" +mixinExtras-expressions = "io.github.llamalad7:mixinextras-expressions:0.0.6" +jgraphx = "com.github.vlsi.mxgraph:jgraphx:4.2.2" # GrammarKit jflex-lib = "org.jetbrains.idea:jflex:1.7.0-b7f882a" Index: src/main/kotlin/platform/mixin/util/AsmUtil.kt =================================================================== --- src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision 0649022ea7495569c4a54abfea2d1d6df86dc219) +++ src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision 62e8d4ceea59f88f7423fd016ff4d04e505d18a6) @@ -183,6 +183,12 @@ val ClassNode.shortName get() = internalNameToShortName(name) +val Type.shortName get() = className.substringAfterLast('.').replace('$', '.') + +fun shortDescString(desc: String) = Type.getArgumentTypes(desc).joinToString(prefix = "(", postfix = ")") { + it.shortName +} + private val INNER_CLASS_NODES_KEY = Key.create>>("mcdev.innerClassNodes") /** @@ -776,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() } @@ -1094,6 +1100,26 @@ return ClassAndMethodNode(clazz, method) } +// AbstractInsnNode + +val AbstractInsnNode.nextRealInsn: AbstractInsnNode? + get() { + var insn = next + while (insn != null && insn.opcode < 0) { + insn = insn.next + } + return insn + } + +val AbstractInsnNode.previousRealInsn: AbstractInsnNode? + get() { + var insn = previous + while (insn != null && insn.opcode < 0) { + insn = insn.previous + } + return insn + } + // Textifier fun ClassNode.textify(): String { Index: src/main/kotlin/util/psi-utils.kt =================================================================== --- src/main/kotlin/util/psi-utils.kt (revision 0649022ea7495569c4a54abfea2d1d6df86dc219) +++ src/main/kotlin/util/psi-utils.kt (revision 62e8d4ceea59f88f7423fd016ff4d04e505d18a6) @@ -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 @@ -373,22 +383,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)