Skip to content

Commit 3412b35

Browse files
committed
Add inspection for when CTOR_HEAD with enforce=POST_INIT doesn't target a field
1 parent 11870b4 commit 3412b35

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

src/main/kotlin/platform/mixin/handlers/injectionPoint/CtorHeadInjectionPoint.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class CtorHeadInjectionPoint : InjectionPoint<PsiElement>() {
9090
return null
9191
}
9292

93-
private enum class EnforceMode {
93+
enum class EnforceMode {
9494
DEFAULT, POST_DELEGATE, POST_INIT
9595
}
9696

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Minecraft Development for IntelliJ
3+
*
4+
* https://mcdev.io/
5+
*
6+
* Copyright (C) 2024 minecraft-dev
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as published
10+
* by the Free Software Foundation, version 3.0 only.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
package com.demonwav.mcdev.platform.mixin.inspection.injector
22+
23+
import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler
24+
import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.AtResolver
25+
import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CtorHeadInjectionPoint
26+
import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection
27+
import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix
28+
import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember
29+
import com.demonwav.mcdev.platform.mixin.util.MixinConstants
30+
import com.demonwav.mcdev.platform.mixin.util.isConstructor
31+
import com.demonwav.mcdev.util.constantValue
32+
import com.demonwav.mcdev.util.enumValueOfOrNull
33+
import com.intellij.codeInspection.ProblemsHolder
34+
import com.intellij.psi.JavaElementVisitor
35+
import com.intellij.psi.PsiAnnotation
36+
import com.intellij.psi.PsiClass
37+
import com.intellij.psi.PsiElementVisitor
38+
import com.intellij.psi.PsiModifierList
39+
import com.intellij.psi.util.parents
40+
import org.objectweb.asm.Opcodes
41+
42+
class CtorHeadPostInitInspection : MixinInspection() {
43+
override fun getStaticDescription() = "Reports when CTOR_HEAD with enforce=POST_INIT doesn't target a field"
44+
45+
override fun buildVisitor(holder: ProblemsHolder): PsiElementVisitor = object : JavaElementVisitor() {
46+
override fun visitAnnotation(annotation: PsiAnnotation) {
47+
if (!annotation.hasQualifiedName(MixinConstants.Annotations.AT)) {
48+
return
49+
}
50+
if (annotation.findDeclaredAttributeValue("value")?.constantValue != "CTOR_HEAD") {
51+
return
52+
}
53+
54+
val atArgs = annotation.findDeclaredAttributeValue("args") ?: return
55+
val enforce = AtResolver.getArgs(annotation)["enforce"]
56+
?.let { enumValueOfOrNull<CtorHeadInjectionPoint.EnforceMode>(it) }
57+
?: CtorHeadInjectionPoint.EnforceMode.DEFAULT
58+
if (enforce != CtorHeadInjectionPoint.EnforceMode.POST_INIT) {
59+
return
60+
}
61+
62+
val injectorAnnotation = annotation.parents(false)
63+
.takeWhile { it !is PsiClass }
64+
.filterIsInstance<PsiAnnotation>()
65+
.firstOrNull { it.parent is PsiModifierList }
66+
?: return
67+
val handler = injectorAnnotation.qualifiedName
68+
?.let { MixinAnnotationHandler.forMixinAnnotation(it, holder.project) }
69+
?: return
70+
val targets = handler.resolveTarget(injectorAnnotation).filterIsInstance<MethodTargetMember>()
71+
72+
if (targets.any {
73+
it.classAndMethod.method.isConstructor &&
74+
AtResolver(annotation, it.classAndMethod.clazz, it.classAndMethod.method)
75+
.resolveInstructions()
76+
.any { insn -> insn.insn.previous?.opcode != Opcodes.PUTFIELD }
77+
}
78+
) {
79+
holder.registerProblem(
80+
atArgs,
81+
"CTOR_HEAD with enforce=POST_INIT doesn't target a field",
82+
AnnotationAttributeFix(annotation, "args" to null)
83+
)
84+
}
85+
}
86+
}
87+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,14 @@
912912
level="WARNING"
913913
hasStaticDescription="true"
914914
implementationClass="com.demonwav.mcdev.platform.mixin.inspection.injector.UnnecessaryUnsafeInspection"/>
915+
<localInspection displayName="CTOR_HEAD with enforce=POST_INIT doesn't target a field"
916+
shortName="CtorHeadPostInit"
917+
groupName="Mixin"
918+
language="JAVA"
919+
enabledByDefault="true"
920+
level="WARNING"
921+
hasStaticDescription="true"
922+
implementationClass="com.demonwav.mcdev.platform.mixin.inspection.injector.CtorHeadPostInitInspection"/>
915923
<!--endregion-->
916924

917925
<!--region Overwrite Inspections -->

0 commit comments

Comments
 (0)