User: joe Date: 21 Jul 24 16:22 Revision: 3f2c1217554a95475dca6c60060f0dbfa6506d7a Summary: Implement JUMP injection point (without source navigation) TeamCity URL: http://ci.mcdev.io:80/viewModification.html?tab=vcsModificationFiles&modId=9492&personal=false Index: src/main/kotlin/platform/mixin/handlers/injectionPoint/JumpInjectionPoint.kt =================================================================== --- src/main/kotlin/platform/mixin/handlers/injectionPoint/JumpInjectionPoint.kt (revision 3f2c1217554a95475dca6c60060f0dbfa6506d7a) +++ src/main/kotlin/platform/mixin/handlers/injectionPoint/JumpInjectionPoint.kt (revision 3f2c1217554a95475dca6c60060f0dbfa6506d7a) @@ -0,0 +1,102 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2024 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.mixin.handlers.injectionPoint + +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector +import com.demonwav.mcdev.platform.mixin.util.findOrConstructSourceMethod +import com.demonwav.mcdev.util.constantValue +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import org.objectweb.asm.Opcodes +import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.JumpInsnNode +import org.objectweb.asm.tree.MethodNode + +class JumpInjectionPoint : InjectionPoint() { + companion object { + private val VALID_OPCODES = setOf( + Opcodes.IFEQ, + Opcodes.IFNE, + Opcodes.IFLT, + Opcodes.IFGE, + Opcodes.IFGT, + Opcodes.IFLE, + Opcodes.IF_ICMPEQ, + Opcodes.IF_ICMPNE, + Opcodes.IF_ICMPLT, + Opcodes.IF_ICMPGE, + Opcodes.IF_ICMPGT, + Opcodes.IF_ICMPLE, + Opcodes.IF_ACMPEQ, + Opcodes.IF_ACMPNE, + Opcodes.GOTO, + Opcodes.JSR, + Opcodes.IFNULL, + Opcodes.IFNONNULL, + ) + } + + override fun createNavigationVisitor( + at: PsiAnnotation, + target: MixinSelector?, + targetClass: PsiClass + ): NavigationVisitor? { + // TODO: jump target source navigation? This would be extremely hard + return null + } + + override fun doCreateCollectVisitor( + at: PsiAnnotation, + target: MixinSelector?, + targetClass: ClassNode, + mode: CollectVisitor.Mode + ): CollectVisitor { + val opcode = (at.findDeclaredAttributeValue("opcode")?.constantValue as? Int) + ?.takeIf { it in VALID_OPCODES } ?: -1 + return MyCollectVisitor(at.project, targetClass, mode, opcode) + } + + override fun createLookup( + targetClass: ClassNode, + result: CollectVisitor.Result + ): LookupElementBuilder? { + return null + } + + private class MyCollectVisitor( + private val project: Project, + private val clazz: ClassNode, + mode: Mode, + private val opcode: Int + ) : CollectVisitor(mode) { + override fun accept(methodNode: MethodNode) { + val insns = methodNode.instructions ?: return + insns.iterator().forEachRemaining { insn -> + if (insn is JumpInsnNode && (opcode == -1 || insn.opcode == opcode)) { + addResult(insn, methodNode.findOrConstructSourceMethod(clazz, project)) + } + } + } + } +} Index: src/main/resources/META-INF/plugin.xml =================================================================== --- src/main/resources/META-INF/plugin.xml (revision 2293169cc59ae81f90be1ec2fb6216916473dcab) +++ src/main/resources/META-INF/plugin.xml (revision 3f2c1217554a95475dca6c60060f0dbfa6506d7a) @@ -195,6 +195,7 @@ +