User: joe Date: 23 Jan 24 14:15 Revision: 3412b3554fec87edc87fe95d5fd95ad811270312 Summary: Add inspection for when CTOR_HEAD with enforce=POST_INIT doesn't target a field TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=9035&personal=false Index: src/main/kotlin/platform/mixin/handlers/injectionPoint/CtorHeadInjectionPoint.kt =================================================================== --- src/main/kotlin/platform/mixin/handlers/injectionPoint/CtorHeadInjectionPoint.kt (revision 11870b464c1bde4f6ee793cc6ba284a20e5464c0) +++ src/main/kotlin/platform/mixin/handlers/injectionPoint/CtorHeadInjectionPoint.kt (revision 3412b3554fec87edc87fe95d5fd95ad811270312) @@ -90,7 +90,7 @@ return null } - private enum class EnforceMode { + enum class EnforceMode { DEFAULT, POST_DELEGATE, POST_INIT } Index: src/main/kotlin/platform/mixin/inspection/injector/CtorHeadPostInitInspection.kt =================================================================== --- src/main/kotlin/platform/mixin/inspection/injector/CtorHeadPostInitInspection.kt (revision 3412b3554fec87edc87fe95d5fd95ad811270312) +++ src/main/kotlin/platform/mixin/inspection/injector/CtorHeadPostInitInspection.kt (revision 3412b3554fec87edc87fe95d5fd95ad811270312) @@ -0,0 +1,87 @@ +/* + * 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.inspection.injector + +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.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.MethodTargetMember +import com.demonwav.mcdev.platform.mixin.util.MixinConstants +import com.demonwav.mcdev.platform.mixin.util.isConstructor +import com.demonwav.mcdev.util.constantValue +import com.demonwav.mcdev.util.enumValueOfOrNull +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.psi.JavaElementVisitor +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiModifierList +import com.intellij.psi.util.parents +import org.objectweb.asm.Opcodes + +class CtorHeadPostInitInspection : MixinInspection() { + override fun getStaticDescription() = "Reports when CTOR_HEAD with enforce=POST_INIT doesn't target a field" + + override fun buildVisitor(holder: ProblemsHolder): PsiElementVisitor = object : JavaElementVisitor() { + override fun visitAnnotation(annotation: PsiAnnotation) { + if (!annotation.hasQualifiedName(MixinConstants.Annotations.AT)) { + return + } + if (annotation.findDeclaredAttributeValue("value")?.constantValue != "CTOR_HEAD") { + return + } + + val atArgs = annotation.findDeclaredAttributeValue("args") ?: return + val enforce = AtResolver.getArgs(annotation)["enforce"] + ?.let { enumValueOfOrNull(it) } + ?: CtorHeadInjectionPoint.EnforceMode.DEFAULT + if (enforce != CtorHeadInjectionPoint.EnforceMode.POST_INIT) { + return + } + + val injectorAnnotation = annotation.parents(false) + .takeWhile { it !is PsiClass } + .filterIsInstance() + .firstOrNull { it.parent is PsiModifierList } + ?: return + val handler = injectorAnnotation.qualifiedName + ?.let { MixinAnnotationHandler.forMixinAnnotation(it, holder.project) } + ?: return + val targets = handler.resolveTarget(injectorAnnotation).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 } + } + ) { + holder.registerProblem( + atArgs, + "CTOR_HEAD with enforce=POST_INIT doesn't target a field", + AnnotationAttributeFix(annotation, "args" to null) + ) + } + } + } +} Index: src/main/resources/META-INF/plugin.xml =================================================================== --- src/main/resources/META-INF/plugin.xml (revision 11870b464c1bde4f6ee793cc6ba284a20e5464c0) +++ src/main/resources/META-INF/plugin.xml (revision 3412b3554fec87edc87fe95d5fd95ad811270312) @@ -912,6 +912,14 @@ level="WARNING" hasStaticDescription="true" implementationClass="com.demonwav.mcdev.platform.mixin.inspection.injector.UnnecessaryUnsafeInspection"/> +