diff --git a/src/main/kotlin/platform/mixin/completion/MixinCompletionContributor.kt b/src/main/kotlin/platform/mixin/completion/MixinCompletionContributor.kt index 300569fb6..72cee99cf 100644 --- a/src/main/kotlin/platform/mixin/completion/MixinCompletionContributor.kt +++ b/src/main/kotlin/platform/mixin/completion/MixinCompletionContributor.kt @@ -21,6 +21,7 @@ package com.demonwav.mcdev.platform.mixin.completion import com.demonwav.mcdev.platform.mixin.reference.MixinReferences +import com.demonwav.mcdev.platform.mixin.handlers.ShadowTargetResolver import com.demonwav.mcdev.platform.mixin.util.findShadowTargets import com.demonwav.mcdev.platform.mixin.util.isMixin import com.demonwav.mcdev.util.constantStringValue @@ -124,7 +125,9 @@ class MixinCompletionContributor : CompletionContributor() { } // Process methods and fields from target class - val elements = findShadowTargets(psiClass, start, superMixin != null) + val extensionTargets = ShadowTargetResolver.EP_NAME.extensionList.asSequence() + .flatMap { it.findCompletionTargets(start) } + val elements = (findShadowTargets(psiClass, start, superMixin != null) + extensionTargets) .filter { val name = it.name StringUtil.isJavaIdentifier(name) && prefixMatcher.prefixMatches(name) diff --git a/src/main/kotlin/platform/mixin/handlers/ShadowHandler.kt b/src/main/kotlin/platform/mixin/handlers/ShadowHandler.kt index e248976f2..3d306fc54 100644 --- a/src/main/kotlin/platform/mixin/handlers/ShadowHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/ShadowHandler.kt @@ -49,7 +49,7 @@ class ShadowHandler : MixinMemberAnnotationHandler { if (hasAliases(annotation)) return emptyList() val member = annotation.parentOfType() ?: return emptyList() val name = getEffectiveName(annotation, member) ?: return emptyList() - return when (member) { + val targetMembers = when (member) { is PsiMethod -> listOfNotNull( targetClass.findMethod(MemberReference(name, member.descriptor)) ?.let { MethodTargetMember(targetClass, it) }, @@ -59,6 +59,10 @@ class ShadowHandler : MixinMemberAnnotationHandler { ) else -> emptyList() } + if (targetMembers.isNotEmpty()) return targetMembers + return ShadowTargetResolver.EP_NAME.extensionList.flatMap { + it.resolveTarget(annotation, targetClass, member, name) + } } override fun isUnresolved(annotation: PsiAnnotation, targetClass: ClassNode): InsnResolutionInfo.Failure? { diff --git a/src/main/kotlin/platform/mixin/handlers/ShadowTargetResolver.kt b/src/main/kotlin/platform/mixin/handlers/ShadowTargetResolver.kt new file mode 100644 index 000000000..5997f3200 --- /dev/null +++ b/src/main/kotlin/platform/mixin/handlers/ShadowTargetResolver.kt @@ -0,0 +1,44 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2026 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 + +import com.demonwav.mcdev.platform.mixin.util.MixinTargetMember +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiMember +import com.intellij.psi.PsiClass +import org.objectweb.asm.tree.ClassNode + +/** Supplies shadow targets contributed by other transformations of the same target class. */ +interface ShadowTargetResolver { + fun resolveTarget( + shadow: PsiAnnotation, + targetClass: ClassNode, + member: PsiMember, + effectiveName: String, + ): List + + fun findCompletionTargets(mixinClass: PsiClass): Sequence = emptySequence() + + companion object { + val EP_NAME = ExtensionPointName.create("com.demonwav.minecraft-dev.shadowTargetResolver") + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index bce7b67e5..e2c4094b3 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -111,6 +111,8 @@ +