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"/>
+