2020
2121package com.demonwav.mcdev.platform.mixin.inspection.injector
2222
23+ import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler
2324import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler
25+ import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CollectVisitor
2426import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection
2527import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix
26- import com.demonwav.mcdev.platform.mixin.util.ClassAndMethodNode
28+ import com.demonwav.mcdev.platform.mixin.util.LocalInfo
2729import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember
2830import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.MODIFY_VARIABLE
2931import com.demonwav.mcdev.platform.mixin.util.hasAccess
30- import com.demonwav.mcdev.util.constantValue
31- import com.demonwav.mcdev.util.descriptor
3232import com.demonwav.mcdev.util.findAnnotation
33- import com.demonwav.mcdev.util.ifEmpty
33+ import com.demonwav.mcdev.util.findModule
3434import com.intellij.codeInspection.ProblemsHolder
3535import com.intellij.psi.JavaElementVisitor
3636import com.intellij.psi.PsiAnnotation
3737import com.intellij.psi.PsiElementVisitor
3838import com.intellij.psi.PsiMethod
39- import com.intellij.psi.PsiType
4039import org.objectweb.asm.Opcodes
4140import org.objectweb.asm.Type
4241
@@ -48,15 +47,14 @@ class ModifyVariableArgsOnlyInspection : MixinInspection() {
4847 return object : JavaElementVisitor () {
4948 override fun visitMethod (method : PsiMethod ) {
5049 val modifyVariable = method.findAnnotation(MODIFY_VARIABLE ) ? : return
51- val wantedType = method.parameterList.getParameter(0 )?.type ? : return
50+ val localType = method.parameterList.getParameter(0 )?.type ? : return
5251 val problemElement = modifyVariable.nameReferenceElement ? : return
5352
54- val targets = MixinAnnotationHandler .resolveTarget(modifyVariable).ifEmpty { return }
55- val methodTargets = targets.asSequence()
56- .filterIsInstance<MethodTargetMember >()
57- .map { it.classAndMethod }
53+ val injector =
54+ MixinAnnotationHandler .forMixinAnnotation(MODIFY_VARIABLE ) as ? InjectorAnnotationHandler ? : return
55+ val localInfo = LocalInfo .fromAnnotation(localType, modifyVariable)
5856
59- if (shouldReport(modifyVariable, wantedType, methodTargets )) {
57+ if (shouldReport(localInfo, injector, modifyVariable )) {
6058 val description = " @ModifyVariable may be argsOnly = true"
6159 holder.registerProblem(
6260 problemElement,
@@ -70,46 +68,47 @@ class ModifyVariableArgsOnlyInspection : MixinInspection() {
7068
7169 companion object {
7270 fun shouldReport (
73- annotation : PsiAnnotation ,
74- wantedType : PsiType ,
75- methodTargets : Sequence < ClassAndMethodNode > ,
71+ localInfo : LocalInfo ,
72+ injector : InjectorAnnotationHandler ,
73+ injectorAnnotation : PsiAnnotation ,
7674 ): Boolean {
77- if (annotation.findDeclaredAttributeValue( " argsOnly" )?.constantValue == true ) {
75+ if (localInfo. argsOnly) {
7876 return false
7977 }
8078
81- val ordinal = (annotation.findDeclaredAttributeValue(" ordinal" )?.constantValue as ? Int? )
82- ?.takeIf { it != - 1 }
83- val index = (annotation.findDeclaredAttributeValue(" index" )?.constantValue as ? Int? )
84- ?.takeIf { it != - 1 }
85- if (ordinal == null && index == null && annotation.findDeclaredAttributeValue(" name" ) != null ) {
86- return false
87- }
79+ val localInfo = LocalInfo (
80+ localInfo.type,
81+ argsOnly = true ,
82+ localInfo.index,
83+ localInfo.ordinal,
84+ localInfo.names,
85+ )
86+
87+ val module = injectorAnnotation.findModule() ? : return false
8888
89- val wantedDesc = wantedType.descriptor
89+ for (targetMember in MixinAnnotationHandler .resolveTarget(injectorAnnotation)) {
90+ val (targetClass, targetMethod) = (targetMember as ? MethodTargetMember )?.classAndMethod ? : continue
91+ val resolvedInsns = injector.resolveInstructions(injectorAnnotation, targetClass, targetMethod)
9092
91- for ((_, targetMethod) in methodTargets) {
92- val argTypes = mutableListOf<String ?>()
93- if (! targetMethod.hasAccess(Opcodes .ACC_STATIC )) {
94- argTypes + = null
93+ if (resolvedInsns.isEmpty()) {
94+ // unresolved injection point, don't report that we can be argsOnly
95+ return false
9596 }
96- for (arg in Type .getArgumentTypes(targetMethod.desc)) {
97- argTypes + = arg.descriptor
98- if (arg.size == 2 ) {
99- argTypes + = null
100- }
97+
98+ var argumentsSize = Type .getArgumentsAndReturnSizes(targetMethod.desc) shr 2
99+ if (targetMethod.hasAccess(Opcodes .ACC_STATIC )) {
100+ argumentsSize--
101101 }
102102
103- if (ordinal != null ) {
104- if (argTypes.asSequence().filter { it == wantedDesc }.count() <= ordinal) {
105- return false
106- }
107- } else if (index != null ) {
108- if (argTypes.size <= index) {
109- return false
110- }
111- } else {
112- if (argTypes.asSequence().filter { it == wantedDesc }.count() != 1 ) {
103+ for (insn in resolvedInsns) {
104+ val matchedLocals = localInfo.matchLocals(
105+ module,
106+ targetClass,
107+ targetMethod,
108+ insn.insn,
109+ CollectVisitor .Mode .RESOLUTION
110+ )
111+ if (matchedLocals.isNullOrEmpty() || matchedLocals.any { it.index >= argumentsSize }) {
113112 return false
114113 }
115114 }
0 commit comments