diff --git a/src/main/kotlin/platform/mixin/expression/gui/MEShowFlowAction.kt b/src/main/kotlin/platform/mixin/expression/gui/MEShowFlowAction.kt index 17f513f30..5f9ebcda8 100644 --- a/src/main/kotlin/platform/mixin/expression/gui/MEShowFlowAction.kt +++ b/src/main/kotlin/platform/mixin/expression/gui/MEShowFlowAction.kt @@ -93,8 +93,8 @@ class MEShowFlowAction : AnAction() { fun resolveMixinMethodString(): Sequence { val string = element.parentOfType() ?: return emptySequence() - return MethodReference.resolve(string)?.map { (clazz, method) -> - Resolved(clazz, method) + return MethodReference.resolve(string)?.map { member -> + Resolved(member.classAndMethod.clazz, member.classAndMethod.method) }.orEmpty() } diff --git a/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt b/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt index 0c56329d3..af4c460c2 100644 --- a/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt @@ -22,6 +22,7 @@ package com.demonwav.mcdev.platform.mixin.handlers import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.LocalVariables import com.demonwav.mcdev.platform.mixin.util.callbackInfoReturnableType import com.demonwav.mcdev.platform.mixin.util.callbackInfoType @@ -49,6 +50,7 @@ class InjectAnnotationHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ): List { val returnType = targetMethod.getGenericReturnType(targetClass, annotation.project) @@ -85,7 +87,7 @@ class InjectAnnotationHandler : InjectorAnnotationHandler() { if (localCapture != "NO_CAPTURE") { annotation.findModule()?.let { module -> var commonLocalsPrefix: MutableList? = null - val resolvedInsns = resolveInstructions(annotation, targetClass, targetMethod).ifEmpty { return@let } + val resolvedInsns = resolveInstructions(annotation, targetClass, targetMethod, enclosingSelector).ifEmpty { return@let } for (insn in resolvedInsns) { val locals = LocalVariables.getLocals(module, targetClass, targetMethod, insn.insn) ?.filterNotNull() diff --git a/src/main/kotlin/platform/mixin/handlers/InjectorAnnotationHandler.kt b/src/main/kotlin/platform/mixin/handlers/InjectorAnnotationHandler.kt index 9237e3e27..3e9349f0c 100644 --- a/src/main/kotlin/platform/mixin/handlers/InjectorAnnotationHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/InjectorAnnotationHandler.kt @@ -26,9 +26,11 @@ import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CollectVisitor import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.InsnResolutionInfo import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.reference.DescSelectorParser +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.reference.isMiscDynamicSelector import com.demonwav.mcdev.platform.mixin.reference.parseMixinSelector import com.demonwav.mcdev.platform.mixin.util.ClassAndMethodNode +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinTargetMember import com.demonwav.mcdev.platform.mixin.util.getGenericParameterTypes @@ -72,7 +74,11 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { val (clazz, methods) = pair methods.firstNotNullOfOrNull { method -> if (selector.matchMethod(method, clazz)) { - MethodTargetMember(clazz, method) + ContextAwareMethodTargetMember( + clazz, + method, + selector, + ) } else { null } @@ -88,8 +94,13 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { } return resolveTarget(annotation, targetClass).map { targetMember -> - val targetMethod = targetMember as? MethodTargetMember ?: return@map InsnResolutionInfo.Failure() - isUnresolved(annotation, targetClass, targetMethod.classAndMethod.method) ?: return@isUnresolved null + val targetMethod = (targetMember as? MethodTargetMember)?.classAndMethod ?: return@map InsnResolutionInfo.Failure() + isUnresolved( + annotation, + targetClass, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + ) ?: return@isUnresolved null }.reduceOrNull(InsnResolutionInfo.Failure::combine) ?: InsnResolutionInfo.Failure() } @@ -99,16 +110,22 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector? ): InsnResolutionInfo.Failure? { return annotation.findAttributeValue(getAtKey(annotation))?.findAnnotations() .ifNullOrEmpty { return InsnResolutionInfo.Failure() }!! - .firstNotNullOfOrNull { AtResolver(it, targetClass, targetMethod).isUnresolved() } + .firstNotNullOfOrNull { AtResolver(it, targetClass, targetMethod, enclosingSelector).isUnresolved() } } override fun resolveForNavigation(annotation: PsiAnnotation, targetClass: ClassNode): List { return resolveTarget(annotation, targetClass).flatMap { targetMember -> - val targetMethod = targetMember as? MethodTargetMember ?: return@flatMap emptyList() - resolveForNavigation(annotation, targetMethod.classAndMethod.clazz, targetMethod.classAndMethod.method) + val targetMethod = (targetMember as? MethodTargetMember)?.classAndMethod ?: return@flatMap emptyList() + resolveForNavigation( + annotation, + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + ) } } @@ -116,10 +133,11 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector? ): List { return annotation.findAttributeValue(getAtKey(annotation))?.findAnnotations() .ifNullOrEmpty { return emptyList() }!! - .flatMap { AtResolver(it, targetClass, targetMethod).resolveNavigationTargets() } + .flatMap { AtResolver(it, targetClass, targetMethod, enclosingSelector).resolveNavigationTargets() } } fun resolveInstructions(annotation: PsiAnnotation) = annotation.cached(PsiModificationTracker.MODIFICATION_COUNT) { @@ -131,7 +149,12 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { return resolveTarget(annotation, targetClass) .flatMap { targetMember -> val targetMethod = (targetMember as? MethodTargetMember)?.classAndMethod ?: return@flatMap emptyList() - resolveInstructions(annotation, targetMethod.clazz, targetMethod.method).map { result -> + resolveInstructions( + annotation, + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + ).map { result -> InsnResult(targetMethod, result) } } @@ -141,6 +164,7 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, mode: CollectVisitor.Mode = CollectVisitor.Mode.RESOLUTION, ): List> { val cache = annotation.cached(PsiModificationTracker.MODIFICATION_COUNT) { @@ -149,7 +173,7 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { return cache.computeIfAbsent(ClassAndMethodNode(targetClass, targetMethod) to mode) { annotation.findAttributeValue(getAtKey(annotation))?.findAnnotations() .ifNullOrEmpty { return@computeIfAbsent emptyList() }!! - .flatMap { AtResolver(it, targetClass, targetMethod).resolveInstructions(mode) } + .flatMap { AtResolver(it, targetClass, targetMethod, enclosingSelector).resolveInstructions(mode) } } } @@ -162,6 +186,7 @@ abstract class InjectorAnnotationHandler : MixinAnnotationHandler { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector? ): List? open fun isInsnAllowed(insn: AbstractInsnNode, decorations: Map): Boolean { @@ -229,6 +254,7 @@ object DefaultInjectorAnnotationHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ) = null override val isSoft = true diff --git a/src/main/kotlin/platform/mixin/handlers/ModifyArgHandler.kt b/src/main/kotlin/platform/mixin/handlers/ModifyArgHandler.kt index 6fb196501..083b3fc41 100644 --- a/src/main/kotlin/platform/mixin/handlers/ModifyArgHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/ModifyArgHandler.kt @@ -22,6 +22,7 @@ package com.demonwav.mcdev.platform.mixin.handlers import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.fakeResolve import com.demonwav.mcdev.platform.mixin.util.getParameter import com.demonwav.mcdev.platform.mixin.util.toPsiType @@ -48,12 +49,13 @@ class ModifyArgHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ): List? { val index = annotation.findDeclaredAttributeValue("index")?.constantValue as? Int val validSingleArgTypes = mutableSetOf() var mayHaveValidFullSignature = true var validFullSignature: String? = null - val insns = resolveInstructions(annotation, targetClass, targetMethod).ifEmpty { return emptyList() } + val insns = resolveInstructions(annotation, targetClass, targetMethod, enclosingSelector).ifEmpty { return emptyList() } for (insn in insns) { if (insn.insn !is MethodInsnNode) return null diff --git a/src/main/kotlin/platform/mixin/handlers/ModifyArgsHandler.kt b/src/main/kotlin/platform/mixin/handlers/ModifyArgsHandler.kt index 3ec63ae73..7ab1e49b7 100644 --- a/src/main/kotlin/platform/mixin/handlers/ModifyArgsHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/ModifyArgsHandler.kt @@ -22,6 +22,7 @@ package com.demonwav.mcdev.platform.mixin.handlers import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Classes.ARGS import com.demonwav.mcdev.util.Parameter import com.intellij.psi.JavaPsiFacade @@ -44,6 +45,7 @@ class ModifyArgsHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ): List { val argsType = JavaPsiFacade.getElementFactory(annotation.project) .createTypeByFQClassName(ARGS, annotation.resolveScope) diff --git a/src/main/kotlin/platform/mixin/handlers/ModifyConstantHandler.kt b/src/main/kotlin/platform/mixin/handlers/ModifyConstantHandler.kt index bc15541f0..09e1addaf 100644 --- a/src/main/kotlin/platform/mixin/handlers/ModifyConstantHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/ModifyConstantHandler.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.ConstantInjecti import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.InjectionPoint import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.util.findAnnotations import com.intellij.openapi.project.Project import com.intellij.psi.JavaPsiFacade @@ -84,6 +85,7 @@ class ModifyConstantHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ): List { val constantInfos = getConstantInfos(annotation) if (constantInfos == null) { diff --git a/src/main/kotlin/platform/mixin/handlers/ModifyVariableHandler.kt b/src/main/kotlin/platform/mixin/handlers/ModifyVariableHandler.kt index 11284ecfc..e96c33021 100644 --- a/src/main/kotlin/platform/mixin/handlers/ModifyVariableHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/ModifyVariableHandler.kt @@ -25,6 +25,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CollectVisitor import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.InjectionPoint import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.LocalInfo import com.demonwav.mcdev.platform.mixin.util.toPsiType import com.demonwav.mcdev.util.constantStringValue @@ -42,6 +43,7 @@ class ModifyVariableHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ): List? { val module = annotation.findModule() ?: return null @@ -49,7 +51,7 @@ class ModifyVariableHandler : InjectorAnnotationHandler() { val atCode = at?.findAttributeValue("value")?.constantStringValue val isLoadStore = atCode != null && InjectionPoint.byAtCode(atCode) is AbstractLoadInjectionPoint val mode = if (isLoadStore) CollectVisitor.Mode.COMPLETION else CollectVisitor.Mode.RESOLUTION - val targets = resolveInstructions(annotation, targetClass, targetMethod, mode) + val targets = resolveInstructions(annotation, targetClass, targetMethod, enclosingSelector, mode) val targetParamsGroup = ParameterGroup( collectTargetMethodParameters(annotation.project, targetClass, targetMethod), diff --git a/src/main/kotlin/platform/mixin/handlers/RedirectInjectorHandler.kt b/src/main/kotlin/platform/mixin/handlers/RedirectInjectorHandler.kt index 5536a39dc..941bfec26 100644 --- a/src/main/kotlin/platform/mixin/handlers/RedirectInjectorHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/RedirectInjectorHandler.kt @@ -23,6 +23,7 @@ package com.demonwav.mcdev.platform.mixin.handlers import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.NewInsnInjectionPoint import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.AsmDfaUtil import com.demonwav.mcdev.platform.mixin.util.FieldTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember @@ -88,8 +89,9 @@ class RedirectInjectorHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ): List? { - val insns = resolveInstructions(annotation, targetClass, targetMethod).ifEmpty { return emptyList() } + val insns = resolveInstructions(annotation, targetClass, targetMethod, enclosingSelector).ifEmpty { return emptyList() } return getRedirectType(insns[0].insn)?.expectedMethodSignature( annotation, targetClass, diff --git a/src/main/kotlin/platform/mixin/handlers/injectionPoint/AtResolver.kt b/src/main/kotlin/platform/mixin/handlers/injectionPoint/AtResolver.kt index a3b97b028..3b505f21e 100644 --- a/src/main/kotlin/platform/mixin/handlers/injectionPoint/AtResolver.kt +++ b/src/main/kotlin/platform/mixin/handlers/injectionPoint/AtResolver.kt @@ -91,6 +91,7 @@ class AtResolver( private val at: PsiAnnotation, private val targetClass: ClassNode, private val targetMethod: MethodNode, + private val enclosingSelector: MixinSelector?, ) { companion object { fun getInjectionPoint(at: PsiAnnotation): InjectionPoint<*>? { @@ -186,6 +187,7 @@ class AtResolver( at, target, getTargetClass(target), + enclosingSelector, CollectVisitor.Mode.RESOLUTION, ) if (collectVisitor == null) { @@ -211,7 +213,13 @@ class AtResolver( val targetAttr = at.findAttributeValue("target") val target = targetAttr?.let { parseMixinSelector(it) } - val collectVisitor = injectionPoint.createCollectVisitor(at, target, getTargetClass(target), mode) + val collectVisitor = injectionPoint.createCollectVisitor( + at, + target, + getTargetClass(target), + enclosingSelector, + mode + ) ?: return InsnResolutionInfo.Failure() return collectVisitor.visit(targetMethod) @@ -288,7 +296,10 @@ class AtResolver( // Collect all possible targets fun doCollectVariants(injectionPoint: InjectionPoint): List { val visitor = injectionPoint.createCollectVisitor( - at, target, getTargetClass(target), + at, + target, + getTargetClass(target), + enclosingSelector, CollectVisitor.Mode.COMPLETION ) ?: return emptyList() @@ -305,7 +316,8 @@ class AtResolver( } private fun getTargetClass(selector: MixinSelector?): ClassNode { - return selector?.getCustomOwner(targetClass) ?: targetClass + val owner = selector?.getCustomOwner(targetClass) ?: targetClass + return enclosingSelector?.transformTargetClass(owner) ?: owner } } diff --git a/src/main/kotlin/platform/mixin/handlers/injectionPoint/InjectionPoint.kt b/src/main/kotlin/platform/mixin/handlers/injectionPoint/InjectionPoint.kt index ef65ec262..15d97b4fd 100644 --- a/src/main/kotlin/platform/mixin/handlers/injectionPoint/InjectionPoint.kt +++ b/src/main/kotlin/platform/mixin/handlers/injectionPoint/InjectionPoint.kt @@ -127,12 +127,13 @@ abstract class InjectionPoint { at: PsiAnnotation, target: MixinSelector?, targetClass: ClassNode, + enclosingSelector: MixinSelector?, mode: CollectVisitor.Mode, ): CollectVisitor? { return doCreateCollectVisitor(at, target, targetClass, mode)?.also { val isInsideSlice = at.parentOfType()?.hasQualifiedName(SLICE) == true val defaultSpecifier = if (isInsideSlice) InjectionPointSpecifier.FIRST else InjectionPointSpecifier.ALL - addFilters(at, targetClass, it, defaultSpecifier, mode) + addFilters(at, targetClass, it, defaultSpecifier, enclosingSelector, mode) } } @@ -141,9 +142,10 @@ abstract class InjectionPoint { targetClass: ClassNode, collectVisitor: CollectVisitor, defaultSpecifier: InjectionPointSpecifier, + enclosingSelector: MixinSelector?, mode: CollectVisitor.Mode, ) { - addStandardFilters(at, targetClass, collectVisitor, defaultSpecifier, mode) + addStandardFilters(at, targetClass, collectVisitor, defaultSpecifier, enclosingSelector, mode) } fun addStandardFilters( @@ -151,10 +153,11 @@ abstract class InjectionPoint { targetClass: ClassNode, collectVisitor: CollectVisitor, defaultSpecifier: InjectionPointSpecifier, + enclosingSelector: MixinSelector?, mode: CollectVisitor.Mode, ) { addShiftSupport(at, targetClass, collectVisitor) - addSliceFilter(at, targetClass, collectVisitor) + addSliceFilter(at, targetClass, enclosingSelector, collectVisitor) // Make sure the ordinal and specifier filters are last, so that the ordinal only increments once the other // filters have passed, and the specifier acts on the result of them. @@ -170,7 +173,7 @@ abstract class InjectionPoint { collectVisitor.shiftBy = AtResolver.getShift(at) } - protected open fun addSliceFilter(at: PsiAnnotation, targetClass: ClassNode, collectVisitor: CollectVisitor) { + protected open fun addSliceFilter(at: PsiAnnotation, targetClass: ClassNode, enclosingSelector: MixinSelector?, collectVisitor: CollectVisitor) { // resolve slice annotation, take into account slice id if present val sliceId = at.findDeclaredAttributeValue("slice")?.constantStringValue val parentAnnotation = at.parentOfType() ?: return @@ -194,10 +197,10 @@ abstract class InjectionPoint { fun resolveSliceIndex( sliceAt: PsiAnnotation?, - method: MethodNode, + method: MethodNode ): Int? { return sliceAt?.let { - AtResolver(sliceAt, targetClass, method).resolveInstructions() + AtResolver(sliceAt, targetClass, method, enclosingSelector).resolveInstructions() .singleOrNull() ?.let { method.instructions.indexOf(it.insn) } } diff --git a/src/main/kotlin/platform/mixin/handlers/mixinextras/MixinExtrasInjectorAnnotationHandler.kt b/src/main/kotlin/platform/mixin/handlers/mixinextras/MixinExtrasInjectorAnnotationHandler.kt index 1c3592e32..0ee1b0d2b 100644 --- a/src/main/kotlin/platform/mixin/handlers/mixinextras/MixinExtrasInjectorAnnotationHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/mixinextras/MixinExtrasInjectorAnnotationHandler.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.NewInsnInjectionPoint import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.FieldTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.getGenericParameterTypes @@ -115,9 +116,10 @@ abstract class MixinExtrasInjectorAnnotationHandler : InjectorAnnotationHandler( override fun expectedMethodSignature( annotation: PsiAnnotation, targetClass: ClassNode, - targetMethod: MethodNode + targetMethod: MethodNode, + enclosingSelector: MixinSelector? ): List? { - val insns = resolveInstructions(annotation, targetClass, targetMethod) + val insns = resolveInstructions(annotation, targetClass, targetMethod, enclosingSelector) .ifEmpty { return emptyList() } .map { TargetInsn(it.insn, it.decorations) } val signatures = insns.map { insn -> diff --git a/src/main/kotlin/platform/mixin/handlers/mixinextras/WrapMethodHandler.kt b/src/main/kotlin/platform/mixin/handlers/mixinextras/WrapMethodHandler.kt index 0cae1c436..f5030ecf6 100644 --- a/src/main/kotlin/platform/mixin/handlers/mixinextras/WrapMethodHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/mixinextras/WrapMethodHandler.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.InsnResolutionInfo import com.demonwav.mcdev.platform.mixin.inspection.injector.MethodSignature import com.demonwav.mcdev.platform.mixin.inspection.injector.ParameterGroup +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.findSourceElement import com.demonwav.mcdev.platform.mixin.util.getGenericReturnType import com.demonwav.mcdev.platform.mixin.util.mixinExtrasOperationType @@ -42,6 +43,7 @@ class WrapMethodHandler : InjectorAnnotationHandler() { annotation: PsiAnnotation, targetClass: ClassNode, targetMethod: MethodNode, + enclosingSelector: MixinSelector?, ): List { val returnType = targetMethod.getGenericReturnType(targetClass, annotation.project) @@ -64,7 +66,8 @@ class WrapMethodHandler : InjectorAnnotationHandler() { override fun isUnresolved( annotation: PsiAnnotation, targetClass: ClassNode, - targetMethod: MethodNode + targetMethod: MethodNode, + enclosingSelector: MixinSelector? ): InsnResolutionInfo.Failure? { // If we've got a target method that's good enough return null @@ -73,7 +76,8 @@ class WrapMethodHandler : InjectorAnnotationHandler() { override fun resolveForNavigation( annotation: PsiAnnotation, targetClass: ClassNode, - targetMethod: MethodNode + targetMethod: MethodNode, + enclosingSelector: MixinSelector? ): List { val project = annotation.project return targetMethod.findSourceElement( diff --git a/src/main/kotlin/platform/mixin/inspection/MixinAnnotationTargetInspection.kt b/src/main/kotlin/platform/mixin/inspection/MixinAnnotationTargetInspection.kt index d426e8985..35a591811 100644 --- a/src/main/kotlin/platform/mixin/inspection/MixinAnnotationTargetInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/MixinAnnotationTargetInspection.kt @@ -23,6 +23,7 @@ package com.demonwav.mcdev.platform.mixin.inspection import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.AtResolver import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.InsnResolutionInfo +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.AT import com.demonwav.mcdev.util.ifEmpty @@ -51,19 +52,22 @@ class MixinAnnotationTargetInspection : MixinInspection() { if (parentAnnotation == null) { return } - val targets = MixinAnnotationHandler.resolveTarget(parentAnnotation).ifEmpty { return } - val failure = targets.asSequence() + val targetMembers = MixinAnnotationHandler.resolveTarget(parentAnnotation).ifEmpty { return } + val failure = targetMembers.asSequence() .mapNotNull { - (it as? MethodTargetMember)?.classAndMethod + val member = it as? MethodTargetMember + val classAndMethod = member?.classAndMethod + val selector = (it as? ContextAwareMethodTargetMember)?.selector + if (classAndMethod != null) classAndMethod to selector else null } // group by class - .groupBy { it.clazz.name } + .groupBy { it.first.clazz.name } .values.asSequence() // for each class there must be at least one successful match .mapNotNull classLoop@{ methods -> methods .map { - AtResolver(annotation, it.clazz, it.method).isUnresolved() ?: return@classLoop null + AtResolver(annotation, it.first.clazz, it.first.method, it.second).isUnresolved() ?: return@classLoop null } .reduceOrNull(InsnResolutionInfo.Failure::combine) ?: InsnResolutionInfo.Failure() } diff --git a/src/main/kotlin/platform/mixin/inspection/injector/CancellableBeforeSuperCallInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/CancellableBeforeSuperCallInspection.kt index e6c060cf9..95074ce49 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/CancellableBeforeSuperCallInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/CancellableBeforeSuperCallInspection.kt @@ -23,6 +23,7 @@ package com.demonwav.mcdev.platform.mixin.inspection.injector import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.platform.mixin.util.findDelegateConstructorCall @@ -63,17 +64,25 @@ class CancellableBeforeSuperCallInspection : MixinInspection() { val handler = MixinAnnotationHandler.forMixinAnnotation(MixinConstants.Annotations.INJECT)!! as InjectorAnnotationHandler - for (target in MixinAnnotationHandler.resolveTarget(annotation)) { - if (target !is MethodTargetMember) { + for (targetMember in MixinAnnotationHandler.resolveTarget(annotation)) { + if (targetMember !is MethodTargetMember) { continue } - if (!target.classAndMethod.method.isConstructor) { + + val targetMethod = targetMember.classAndMethod + if (!targetMethod.method.isConstructor) { continue } - val methodInsns = target.classAndMethod.method.instructions ?: continue - val delegateCtorCall = target.classAndMethod.method.findDelegateConstructorCall() ?: continue + + val methodInsns = targetMethod.method.instructions ?: continue + val delegateCtorCall = targetMethod.method.findDelegateConstructorCall() ?: continue val instructions = - handler.resolveInstructions(annotation, target.classAndMethod.clazz, target.classAndMethod.method) + handler.resolveInstructions( + annotation, + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + ) if (instructions.any { methodInsns.indexOf(it.insn) <= methodInsns.indexOf(delegateCtorCall) }) { return true } diff --git a/src/main/kotlin/platform/mixin/inspection/injector/CtorHeadPostInitInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/CtorHeadPostInitInspection.kt index 18116dd9b..c9d3825c7 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/CtorHeadPostInitInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/CtorHeadPostInitInspection.kt @@ -25,6 +25,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.AtResolver import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CtorHeadInjectionPoint import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.platform.mixin.util.isConstructor @@ -61,10 +62,14 @@ class CtorHeadPostInitInspection : MixinInspection() { .filterIsInstance() if (targets.any { - it.classAndMethod.method.isConstructor && - AtResolver(annotation, it.classAndMethod.clazz, it.classAndMethod.method) - .resolveInstructions() - .any { insn -> insn.insn.previous?.opcode != Opcodes.PUTFIELD } + val targetMethod = it.classAndMethod + targetMethod.method.isConstructor && + AtResolver( + annotation, + targetMethod.clazz, + targetMethod.method, + (it as? ContextAwareMethodTargetMember)?.selector + ).resolveInstructions().any { insn -> insn.insn.previous?.opcode != Opcodes.PUTFIELD } } ) { holder.registerProblem( diff --git a/src/main/kotlin/platform/mixin/inspection/injector/DisallowedTargetInsnInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/DisallowedTargetInsnInspection.kt index b0e235a31..135e41a27 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/DisallowedTargetInsnInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/DisallowedTargetInsnInspection.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.AtResolver import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.platform.mixin.util.mixinTargets @@ -51,11 +52,13 @@ class DisallowedTargetInsnInspection : MixinInspection() { return@any false } - AtResolver(annotation, targetMember.classAndMethod.clazz, targetMember.classAndMethod.method) - .resolveInstructions() - .any { - !injector.isInsnAllowed(it.insn, it.decorations) - } + val targetMethod = targetMember.classAndMethod + AtResolver( + annotation, + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + ).resolveInstructions().any { !injector.isInsnAllowed(it.insn, it.decorations) } } } diff --git a/src/main/kotlin/platform/mixin/inspection/injector/InjectIntoConstructorInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/InjectIntoConstructorInspection.kt index e878e59c7..c39632608 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/InjectIntoConstructorInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/InjectIntoConstructorInspection.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.AtResolver import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.INJECT import com.demonwav.mcdev.platform.mixin.util.isConstructor @@ -72,13 +73,18 @@ class InjectIntoConstructorInspection : MixinInspection() { if (target !is MethodTargetMember || !target.classAndMethod.method.isConstructor) { continue } - val (targetClass, targetMethod) = target.classAndMethod + val targetMethod = target.classAndMethod for (at in ats) { val isUnsafe = at.findDeclaredAttributeValue("unsafe")?.constantValue as? Boolean ?: (isFabric && allowOnFabric) - val instructions = AtResolver(at, targetClass, targetMethod).resolveInstructions() + val instructions = AtResolver( + at, + targetMethod.clazz, + targetMethod.method, + (target as? ContextAwareMethodTargetMember)?.selector + ).resolveInstructions() if (!isUnsafe && instructions.any { it.insn.opcode != Opcodes.RETURN }) { val atClass = at.nameReferenceElement?.resolve() as? PsiClass val atHasUnsafe = !atClass?.findMethodsByName("unsafe", false).isNullOrEmpty() diff --git a/src/main/kotlin/platform/mixin/inspection/injector/InjectorOpcodeInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/InjectorOpcodeInspection.kt index 6acdd9792..b327d5edf 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/InjectorOpcodeInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/InjectorOpcodeInspection.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.AtResolver import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.util.constantValue @@ -77,13 +78,14 @@ class InjectorOpcodeInspection : MixinInspection() { private fun makeSpecifyOpcodeFix(project: Project, at: PsiAnnotation): LocalQuickFix? { val injector = AtResolver.findInjectorAnnotation(at) ?: return null - val targetMethods = - MixinAnnotationHandler.resolveTarget(injector).filterIsInstance() + val targets = MixinAnnotationHandler.resolveTarget(injector) + .filterIsInstance() val possibleOpcodes = mutableSetOf() - for (method in targetMethods) { - val instructions = AtResolver(at, method.classAndMethod.clazz, method.classAndMethod.method) + for (target in targets) { + val targetMethod = target.classAndMethod + val instructions = AtResolver(at, targetMethod.clazz, targetMethod.method, target.selector) .resolveInstructions() for (insn in instructions) { possibleOpcodes += insn.originalInsn.opcode diff --git a/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt index c5ecfeb78..b783c01c4 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.reference.MethodReference +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.COERCE import com.demonwav.mcdev.platform.mixin.util.findDelegateConstructorCall @@ -98,20 +99,24 @@ class InvalidInjectorMethodSignatureInspection : MixinInspection() { val handler = MixinAnnotationHandler.forMixinAnnotation(annotation, annotation.project) as? InjectorAnnotationHandler ?: continue val methodAttribute = annotation.findDeclaredAttributeValue("method") ?: continue - val targetMethods = MethodReference.resolveAllIfNotAmbiguous(methodAttribute) ?: continue + val targetMembers = MethodReference.resolveAllIfNotAmbiguous(methodAttribute) ?: continue - val hasDisallowedInsns = targetMethods.any { classAndMethod -> + val hasDisallowedInsns = targetMembers.any { targetMember -> + val targetMethod = targetMember.classAndMethod handler.resolveInstructions( annotation, - classAndMethod.clazz, - classAndMethod.method + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector ).any { !handler.isInsnAllowed(it.insn, it.decorations) } } if (hasDisallowedInsns) { continue } - for (targetMethod in targetMethods) { + for (targetMember in targetMembers) { + val targetMethod = targetMember.classAndMethod + val selector = (targetMember as? ContextAwareMethodTargetMember)?.selector if (!reportedStatic) { var shouldBeStatic = targetMethod.method.hasAccess(Opcodes.ACC_STATIC) @@ -124,6 +129,7 @@ class InvalidInjectorMethodSignatureInspection : MixinInspection() { annotation, targetMethod.clazz, targetMethod.method, + selector ) shouldBeStatic = insns.any { methodInsns.indexOf(it.insn) <= methodInsns.indexOf(delegateCtorCall) @@ -167,6 +173,7 @@ class InvalidInjectorMethodSignatureInspection : MixinInspection() { annotation, targetMethod.clazz, targetMethod.method, + selector ) ?: continue val annotationName = annotation.nameReferenceElement?.referenceName diff --git a/src/main/kotlin/platform/mixin/inspection/injector/MixinParameterNameInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/MixinParameterNameInspection.kt index e74dc5b32..e5a3693e6 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/MixinParameterNameInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/MixinParameterNameInspection.kt @@ -24,6 +24,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CollectVisitor import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.LocalInfo import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants @@ -127,7 +128,12 @@ class MixinParameterNameInspection : MixinInspection() { if (reportForMainSignature) { val expectedSignatures = - handler.expectedMethodSignature(annotation, target.classAndMethod.clazz, target.classAndMethod.method) + handler.expectedMethodSignature( + annotation, + target.classAndMethod.clazz, + target.classAndMethod.method, + (target as? ContextAwareMethodTargetMember)?.selector + ) ?: return false var anyValidSignatures = false @@ -231,7 +237,8 @@ class MixinParameterNameInspection : MixinInspection() { for (insn in handler.resolveInstructions( annotation, target.classAndMethod.clazz, - target.classAndMethod.method + target.classAndMethod.method, + (target as? ContextAwareMethodTargetMember)?.selector )) { val matchedLocal = localInfo.matchLocals( module, diff --git a/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableArgsOnlyInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableArgsOnlyInspection.kt index 7d522e885..0cb3d4c85 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableArgsOnlyInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableArgsOnlyInspection.kt @@ -25,6 +25,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CollectVisitor import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.LocalInfo import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.MODIFY_VARIABLE @@ -87,24 +88,29 @@ class ModifyVariableArgsOnlyInspection : MixinInspection() { val module = injectorAnnotation.findModule() ?: return false for (targetMember in MixinAnnotationHandler.resolveTarget(injectorAnnotation)) { - val (targetClass, targetMethod) = (targetMember as? MethodTargetMember)?.classAndMethod ?: continue - val resolvedInsns = injector.resolveInstructions(injectorAnnotation, targetClass, targetMethod) + val targetMethod = (targetMember as? MethodTargetMember)?.classAndMethod ?: continue + val resolvedInsns = injector.resolveInstructions( + injectorAnnotation, + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + ) if (resolvedInsns.isEmpty()) { // unresolved injection point, don't report that we can be argsOnly return false } - var argumentsSize = Type.getArgumentsAndReturnSizes(targetMethod.desc) shr 2 - if (targetMethod.hasAccess(Opcodes.ACC_STATIC)) { + var argumentsSize = Type.getArgumentsAndReturnSizes(targetMethod.method.desc) shr 2 + if (targetMethod.method.hasAccess(Opcodes.ACC_STATIC)) { argumentsSize-- } for (insn in resolvedInsns) { val matchedLocals = localInfo.matchLocals( module, - targetClass, - targetMethod, + targetMethod.clazz, + targetMethod.method, insn.insn, CollectVisitor.Mode.RESOLUTION ) diff --git a/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableMayUseNameInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableMayUseNameInspection.kt index 40f541bdd..a8bbb9714 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableMayUseNameInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableMayUseNameInspection.kt @@ -25,6 +25,7 @@ import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CollectVisitor import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.LocalInfo import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.MODIFY_VARIABLE @@ -123,13 +124,18 @@ class ModifyVariableMayUseNameInspection : MixinInspection() { return null } - for (target in injector.resolveTarget(injectorAnnotation, targetClass)) { - val (clazz, method) = (target as? MethodTargetMember)?.classAndMethod ?: continue - for (insn in injector.resolveInstructions(injectorAnnotation, clazz, method)) { + for (targetMember in injector.resolveTarget(injectorAnnotation, targetClass)) { + val targetMethod = (targetMember as? MethodTargetMember)?.classAndMethod ?: continue + for (insn in injector.resolveInstructions( + injectorAnnotation, + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + )) { val matchedLocals = localInfo.matchLocals( module, - clazz, - method, + targetMethod.clazz, + targetMethod.method, insn.insn, CollectVisitor.Mode.RESOLUTION ) ?: return null diff --git a/src/main/kotlin/platform/mixin/inspection/mixinextras/WrapWithConditionValidNonVoidInspection.kt b/src/main/kotlin/platform/mixin/inspection/mixinextras/WrapWithConditionValidNonVoidInspection.kt index 60d5dea89..4dc718553 100644 --- a/src/main/kotlin/platform/mixin/inspection/mixinextras/WrapWithConditionValidNonVoidInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/mixinextras/WrapWithConditionValidNonVoidInspection.kt @@ -23,6 +23,7 @@ package com.demonwav.mcdev.platform.mixin.inspection.mixinextras import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.mixinextras.WrapWithConditionHandler import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.platform.mixin.util.toPsiType @@ -175,19 +176,25 @@ private fun WrapWithConditionHandler.getReplaceWithWrapOpInfo(annotation: PsiAnn var targetType: Type? = null var requiredParameterCount: Int? = null - for (target in MixinAnnotationHandler.resolveTarget(annotation)) { - if (target !is MethodTargetMember) { + for (targetMember in MixinAnnotationHandler.resolveTarget(annotation)) { + if (targetMember !is MethodTargetMember) { continue } - for (insn in resolveInstructions(annotation, target.classAndMethod.clazz, target.classAndMethod.method)) { + val targetMethod = targetMember.classAndMethod + for (insn in resolveInstructions( + annotation, + targetMethod.clazz, + targetMethod.method, + (targetMember as? ContextAwareMethodTargetMember)?.selector + )) { val newTargetType = getValidTargetType(insn.insn) ?: continue if (targetType != null && targetType != newTargetType) { return null } targetType = newTargetType - val newRequiredParameterCount = getRequiredParameterCount(insn.insn, target.classAndMethod.clazz, annotation) + val newRequiredParameterCount = getRequiredParameterCount(insn.insn, targetMethod.clazz, annotation) if (requiredParameterCount != null && requiredParameterCount != newRequiredParameterCount) { return null } diff --git a/src/main/kotlin/platform/mixin/reference/AbstractMethodReference.kt b/src/main/kotlin/platform/mixin/reference/AbstractMethodReference.kt index bf44c146e..5b29663e4 100644 --- a/src/main/kotlin/platform/mixin/reference/AbstractMethodReference.kt +++ b/src/main/kotlin/platform/mixin/reference/AbstractMethodReference.kt @@ -23,6 +23,8 @@ package com.demonwav.mcdev.platform.mixin.reference import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.reference.target.TargetReference import com.demonwav.mcdev.platform.mixin.util.ClassAndMethodNode +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember +import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.bytecode import com.demonwav.mcdev.platform.mixin.util.findMethods import com.demonwav.mcdev.platform.mixin.util.findOrConstructSourceMethod @@ -105,7 +107,7 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference return targets.any { it.findMethods(MemberReference(targetReference.name)).count() > 1 } } - fun resolve(context: PsiElement): Sequence? { + fun resolve(context: PsiElement): Sequence? { val targets = getTargets(context) ?: return null val targetedMethods = when (context) { is PsiArrayInitializerMemberValue -> context.initializers.mapNotNull { it.constantStringValue } @@ -121,15 +123,21 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference private fun resolve( targets: Collection, selector: MixinSelector, - ): Sequence { + ): Sequence { return targets.asSequence() .flatMap { target -> val actualTarget = selector.getCustomOwner(target) - actualTarget.findMethods(selector).map { ClassAndMethodNode(actualTarget, it) } + actualTarget.findMethods(selector).map { + ContextAwareMethodTargetMember( + actualTarget, + it, + selector + ) + } } } - fun resolveAllIfNotAmbiguous(context: PsiElement): List? { + fun resolveAllIfNotAmbiguous(context: PsiElement): List? { val targets = getTargets(context) ?: return null val targetedMethods = when (context) { @@ -152,8 +160,8 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference fun resolveForNavigation(context: PsiElement): Array? { return resolve(context)?.mapNotNull { - it.method.findSourceElement( - it.clazz, + it.classAndMethod.method.findSourceElement( + it.classAndMethod.clazz, context.project, scope = context.resolveScope, canDecompile = true, @@ -163,8 +171,8 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference override fun resolveReference(context: PsiElement): Array { return resolve(context)?.mapNotNull { - it.method.findSourceElement( - it.clazz, + it.classAndMethod.method.findSourceElement( + it.classAndMethod.clazz, context.project, scope = context.resolveScope, canDecompile = false, diff --git a/src/main/kotlin/platform/mixin/reference/MixinSelectors.kt b/src/main/kotlin/platform/mixin/reference/MixinSelectors.kt index 30441f579..6be52b7b4 100644 --- a/src/main/kotlin/platform/mixin/reference/MixinSelectors.kt +++ b/src/main/kotlin/platform/mixin/reference/MixinSelectors.kt @@ -134,6 +134,10 @@ interface MixinSelector { return owner } + fun transformTargetClass(targetClass: ClassNode): ClassNode { + return targetClass + } + /** * Implement this to return false for early-out optimizations, so you don't need to resolve the member in the * navigation visitor diff --git a/src/main/kotlin/platform/mixin/reference/target/TargetReference.kt b/src/main/kotlin/platform/mixin/reference/target/TargetReference.kt index b49b1627b..bc2478e3e 100644 --- a/src/main/kotlin/platform/mixin/reference/target/TargetReference.kt +++ b/src/main/kotlin/platform/mixin/reference/target/TargetReference.kt @@ -25,7 +25,9 @@ import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.AtResolver import com.demonwav.mcdev.platform.mixin.reference.MixinReference import com.demonwav.mcdev.platform.mixin.reference.parseMixinSelector +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.ClassAndMethodNode +import com.demonwav.mcdev.platform.mixin.util.ContextAwareMethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.AT import com.demonwav.mcdev.util.ifEmpty @@ -69,7 +71,7 @@ object TargetReference : PolyReferenceResolver(), MixinReference { * Null is returned when no parent annotation handler could be found, in which case we shouldn't mark this * reference as unresolved. */ - private fun getTargets(at: PsiAnnotation, forUnresolved: Boolean): List? { + private fun getTargetsAndSelectors(at: PsiAnnotation, forUnresolved: Boolean): List>? { val (handler, annotation) = generateSequence(at.parent) { it.parent } .filterIsInstance() .flatMap { it.owner?.annotations?.asSequence() ?: emptySequence() } @@ -81,14 +83,17 @@ object TargetReference : PolyReferenceResolver(), MixinReference { return null } return MixinAnnotationHandler.resolveTarget(annotation) - .mapNotNull { (it as? MethodTargetMember)?.classAndMethod } + .mapNotNull { target -> + val methodTarget = target as? MethodTargetMember ?: return@mapNotNull null + methodTarget.classAndMethod to (methodTarget as? ContextAwareMethodTargetMember)?.selector + } } override fun isUnresolved(context: PsiElement): Boolean { val at = context.parentOfType() ?: return true - val targets = getTargets(at, true)?.ifEmpty { return true } ?: return false - return targets.all { - val failure = AtResolver(at, it.clazz, it.method).isUnresolved() + val targets = getTargetsAndSelectors(at, true)?.ifEmpty { return true } ?: return false + return targets.all { (node, selector) -> + val failure = AtResolver(at, node.clazz, node.method, selector).isUnresolved() // leave it if there is a filter to blame, the target reference was at least resolved failure != null && failure.filterStats.isEmpty() } @@ -96,8 +101,10 @@ object TargetReference : PolyReferenceResolver(), MixinReference { fun resolveNavigationTargets(context: PsiElement): Array? { val at = context.parentOfType() ?: return null - val targets = getTargets(at, false) ?: return null - return targets.flatMap { AtResolver(at, it.clazz, it.method).resolveNavigationTargets() }.toTypedArray() + val targets = getTargetsAndSelectors(at, false) ?: return null + return targets.flatMap { (node, selector) -> + AtResolver(at, node.clazz, node.method, selector).resolveNavigationTargets() + }.toTypedArray() } override fun resolveReference(context: PsiElement): Array { @@ -107,11 +114,12 @@ object TargetReference : PolyReferenceResolver(), MixinReference { override fun collectVariants(context: PsiElement): Array { val at = context.parentOfType() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val targets = getTargets(at, false) ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - return targets.flatMap { target -> - AtResolver(at, target.clazz, target.method).collectTargetVariants { builder -> + val targets = getTargetsAndSelectors(at, false) ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + return targets.flatMap { (node, selector) -> + AtResolver(at, node.clazz, node.method, selector).collectTargetVariants { builder -> builder.completeToLiteral(context) } }.toTypedArray() } } + diff --git a/src/main/kotlin/platform/mixin/util/TargetClass.kt b/src/main/kotlin/platform/mixin/util/TargetClass.kt index 57b75fe59..b57373d77 100644 --- a/src/main/kotlin/platform/mixin/util/TargetClass.kt +++ b/src/main/kotlin/platform/mixin/util/TargetClass.kt @@ -20,7 +20,9 @@ package com.demonwav.mcdev.platform.mixin.util +import com.demonwav.mcdev.platform.mixin.reference.MixinSelector import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.DYNAMIC +import com.demonwav.mcdev.util.MemberReference import com.demonwav.mcdev.util.equivalentTo import com.demonwav.mcdev.util.findAnnotation import com.demonwav.mcdev.util.findMethods @@ -110,12 +112,7 @@ private fun findShadowTargetsDeep(psiClass: PsiClass, start: PsiClass): Sequence .plus(findFields(mixin)?.map { FieldTargetMember(it, actualMixin) }) ?.filterAccessible(psiClass, mixin) ?: emptySequence() } - .distinctBy { - when (it) { - is MethodTargetMember -> it.classAndMethod.method.memberReference - is FieldTargetMember -> it.classAndField.field.memberReference - } - } + .distinctBy { it.getMemberReference() } } sealed class MixinTargetMember(val mixin: PsiClass?) { @@ -133,9 +130,14 @@ sealed class MixinTargetMember(val mixin: PsiClass?) { scope: GlobalSearchScope, canDecompile: Boolean = false ): PsiMember + + abstract fun getMemberReference(): MemberReference } -class FieldTargetMember(val classAndField: ClassAndFieldNode, mixin: PsiClass? = null) : MixinTargetMember(mixin) { +class FieldTargetMember( + val classAndField: ClassAndFieldNode, + mixin: PsiClass? = null +) : MixinTargetMember(mixin) { constructor(clazz: ClassNode, field: FieldNode) : this(ClassAndFieldNode(clazz, field)) override val access = classAndField.field.access @@ -149,9 +151,14 @@ class FieldTargetMember(val classAndField: ClassAndFieldNode, mixin: PsiClass? = scope: GlobalSearchScope, canDecompile: Boolean ) = classAndField.field.findOrConstructSourceField(classAndField.clazz, project, scope, canDecompile) + + override fun getMemberReference(): MemberReference = classAndField.field.memberReference } -class MethodTargetMember(val classAndMethod: ClassAndMethodNode, mixin: PsiClass? = null) : MixinTargetMember(mixin) { +open class MethodTargetMember( + val classAndMethod: ClassAndMethodNode, + mixin: PsiClass? = null +) : MixinTargetMember(mixin) { constructor(clazz: ClassNode, method: MethodNode) : this(ClassAndMethodNode(clazz, method)) override val access = classAndMethod.method.access @@ -165,6 +172,16 @@ class MethodTargetMember(val classAndMethod: ClassAndMethodNode, mixin: PsiClass scope: GlobalSearchScope, canDecompile: Boolean ) = classAndMethod.method.findOrConstructSourceMethod(classAndMethod.clazz, project, scope, canDecompile) + + override fun getMemberReference(): MemberReference = classAndMethod.method.memberReference +} + +class ContextAwareMethodTargetMember( + classAndMethod: ClassAndMethodNode, + mixin: PsiClass? = null, + val selector: MixinSelector? = null +) : MethodTargetMember(classAndMethod, mixin) { + constructor(clazz: ClassNode, method: MethodNode, selector: MixinSelector? = null) : this(ClassAndMethodNode(clazz, method), null, selector) } private fun Sequence.filterAccessible(