User: joe Date: 06 Nov 25 10:56 Revision: e10f75298ac8e65d7ce4aa2224dfff4519a34fb1 Summary: Change @Local and @ModifyVariable argsOnly inspections so they also work if the local is specified by name TeamCity URL: http://ci.mcdev.io:80/viewModification.html?tab=vcsModificationFiles&modId=10227&personal=false Index: src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableArgsOnlyInspection.kt =================================================================== --- src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableArgsOnlyInspection.kt (revision 175d500d634bd6bb193109fe43bcdcec0ccf0733) +++ src/main/kotlin/platform/mixin/inspection/injector/ModifyVariableArgsOnlyInspection.kt (revision e10f75298ac8e65d7ce4aa2224dfff4519a34fb1) @@ -20,23 +20,22 @@ package com.demonwav.mcdev.platform.mixin.inspection.injector +import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler +import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.CollectVisitor import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix -import com.demonwav.mcdev.platform.mixin.util.ClassAndMethodNode +import com.demonwav.mcdev.platform.mixin.util.LocalInfo import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember import com.demonwav.mcdev.platform.mixin.util.MixinConstants.Annotations.MODIFY_VARIABLE import com.demonwav.mcdev.platform.mixin.util.hasAccess -import com.demonwav.mcdev.util.constantValue -import com.demonwav.mcdev.util.descriptor import com.demonwav.mcdev.util.findAnnotation -import com.demonwav.mcdev.util.ifEmpty +import com.demonwav.mcdev.util.findModule import com.intellij.codeInspection.ProblemsHolder import com.intellij.psi.JavaElementVisitor import com.intellij.psi.PsiAnnotation import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiMethod -import com.intellij.psi.PsiType import org.objectweb.asm.Opcodes import org.objectweb.asm.Type @@ -48,15 +47,14 @@ return object : JavaElementVisitor() { override fun visitMethod(method: PsiMethod) { val modifyVariable = method.findAnnotation(MODIFY_VARIABLE) ?: return - val wantedType = method.parameterList.getParameter(0)?.type ?: return + val localType = method.parameterList.getParameter(0)?.type ?: return val problemElement = modifyVariable.nameReferenceElement ?: return - val targets = MixinAnnotationHandler.resolveTarget(modifyVariable).ifEmpty { return } - val methodTargets = targets.asSequence() - .filterIsInstance() - .map { it.classAndMethod } + val injector = + MixinAnnotationHandler.forMixinAnnotation(MODIFY_VARIABLE) as? InjectorAnnotationHandler ?: return + val localInfo = LocalInfo.fromAnnotation(localType, modifyVariable) - if (shouldReport(modifyVariable, wantedType, methodTargets)) { + if (shouldReport(localInfo, injector, modifyVariable)) { val description = "@ModifyVariable may be argsOnly = true" holder.registerProblem( problemElement, @@ -70,46 +68,47 @@ companion object { fun shouldReport( - annotation: PsiAnnotation, - wantedType: PsiType, - methodTargets: Sequence, + localInfo: LocalInfo, + injector: InjectorAnnotationHandler, + injectorAnnotation: PsiAnnotation, ): Boolean { - if (annotation.findDeclaredAttributeValue("argsOnly")?.constantValue == true) { + if (localInfo.argsOnly) { return false } - val ordinal = (annotation.findDeclaredAttributeValue("ordinal")?.constantValue as? Int?) - ?.takeIf { it != -1 } - val index = (annotation.findDeclaredAttributeValue("index")?.constantValue as? Int?) - ?.takeIf { it != -1 } - if (ordinal == null && index == null && annotation.findDeclaredAttributeValue("name") != null) { - return false - } + val localInfo = LocalInfo( + localInfo.type, + argsOnly = true, + localInfo.index, + localInfo.ordinal, + localInfo.names, + ) - val wantedDesc = wantedType.descriptor + val module = injectorAnnotation.findModule() ?: return false - for ((_, targetMethod) in methodTargets) { - val argTypes = mutableListOf() - if (!targetMethod.hasAccess(Opcodes.ACC_STATIC)) { - argTypes += null - } - for (arg in Type.getArgumentTypes(targetMethod.desc)) { - argTypes += arg.descriptor - if (arg.size == 2) { - argTypes += null - } - } + for (targetMember in MixinAnnotationHandler.resolveTarget(injectorAnnotation)) { + val (targetClass, targetMethod) = (targetMember as? MethodTargetMember)?.classAndMethod ?: continue + val resolvedInsns = injector.resolveInstructions(injectorAnnotation, targetClass, targetMethod) - if (ordinal != null) { - if (argTypes.asSequence().filter { it == wantedDesc }.count() <= ordinal) { + if (resolvedInsns.isEmpty()) { + // unresolved injection point, don't report that we can be argsOnly - return false - } + return false + } - } else if (index != null) { - if (argTypes.size <= index) { - return false + + var argumentsSize = Type.getArgumentsAndReturnSizes(targetMethod.desc) shr 2 + if (targetMethod.hasAccess(Opcodes.ACC_STATIC)) { + argumentsSize-- - } + } - } else { - if (argTypes.asSequence().filter { it == wantedDesc }.count() != 1) { + + for (insn in resolvedInsns) { + val matchedLocals = localInfo.matchLocals( + module, + targetClass, + targetMethod, + insn.insn, + CollectVisitor.Mode.RESOLUTION + ) + if (matchedLocals.isNullOrEmpty() || matchedLocals.any { it.index >= argumentsSize }) { return false } } Index: src/main/kotlin/platform/mixin/inspection/mixinextras/LocalArgsOnlyInspection.kt =================================================================== --- src/main/kotlin/platform/mixin/inspection/mixinextras/LocalArgsOnlyInspection.kt (revision 175d500d634bd6bb193109fe43bcdcec0ccf0733) +++ src/main/kotlin/platform/mixin/inspection/mixinextras/LocalArgsOnlyInspection.kt (revision e10f75298ac8e65d7ce4aa2224dfff4519a34fb1) @@ -20,20 +20,21 @@ package com.demonwav.mcdev.platform.mixin.inspection.mixinextras +import com.demonwav.mcdev.platform.mixin.handlers.InjectorAnnotationHandler import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection import com.demonwav.mcdev.platform.mixin.inspection.fix.AnnotationAttributeFix import com.demonwav.mcdev.platform.mixin.inspection.injector.ModifyVariableArgsOnlyInspection -import com.demonwav.mcdev.platform.mixin.util.MethodTargetMember +import com.demonwav.mcdev.platform.mixin.util.LocalInfo import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.platform.mixin.util.unwrapLocalRef import com.demonwav.mcdev.util.constantValue -import com.demonwav.mcdev.util.findContainingMethod -import com.demonwav.mcdev.util.ifEmpty +import com.demonwav.mcdev.util.mapFirstNotNull import com.intellij.codeInspection.ProblemsHolder import com.intellij.psi.JavaElementVisitor import com.intellij.psi.PsiAnnotation import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiMethod import com.intellij.psi.PsiParameter import com.intellij.psi.util.parentOfType @@ -50,17 +51,16 @@ return } val parameter = localAnnotation.parentOfType() ?: return - val method = parameter.findContainingMethod() ?: return + val method = parameter.declarationScope as? PsiMethod ?: return - val targets = method.annotations.flatMap { annotation -> - MixinAnnotationHandler.resolveTarget(annotation).asSequence() - .filterIsInstance() - .map { it.classAndMethod } - }.ifEmpty { return } + val (injector, injectorAnnotation) = method.annotations.mapFirstNotNull { annotation -> + (MixinAnnotationHandler.forMixinAnnotation(annotation, holder.project) as? InjectorAnnotationHandler)?.let { it to annotation } + } ?: return val localType = parameter.type.unwrapLocalRef() + val localInfo = LocalInfo.fromAnnotation(localType, localAnnotation) - if (ModifyVariableArgsOnlyInspection.shouldReport(localAnnotation, localType, targets.asSequence())) { + if (ModifyVariableArgsOnlyInspection.shouldReport(localInfo, injector, injectorAnnotation)) { holder.registerProblem( localAnnotation.nameReferenceElement ?: localAnnotation, "@Local may be argsOnly = true",