User: llamalad7 Date: 10 Jan 23 23:11 Revision: 3bd5b6ddf2408a476330a818a623f03f9033973a Summary: Add basic support for MixinExtras Sugar. Ensures that sugars do not trigger invalid parameter errors, and are preserved when quick fixing such errors. TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=8304&personal=false Index: src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt =================================================================== --- src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt (revision 0002cf5bbe9735608bcf2bdcad66074fd1cac592) +++ src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt (revision 3bd5b6ddf2408a476330a818a623f03f9033973a) @@ -20,6 +20,7 @@ import com.demonwav.mcdev.platform.mixin.util.hasAccess import com.demonwav.mcdev.platform.mixin.util.isAssignable import com.demonwav.mcdev.platform.mixin.util.isConstructor +import com.demonwav.mcdev.platform.mixin.util.isMixinExtrasSugar import com.demonwav.mcdev.util.Parameter import com.demonwav.mcdev.util.fullQualifiedName import com.demonwav.mcdev.util.synchronize @@ -232,11 +233,12 @@ allowCoerce: Boolean ): CheckResult { val parameters = parameterList.parameters + val parametersWithoutSugar = parameters.dropLastWhile { it.isMixinExtrasSugar }.toTypedArray() var pos = 0 for (group in expected) { // Check if parameter group matches - if (group.match(parameters, pos, allowCoerce)) { + if (group.match(parametersWithoutSugar, pos, allowCoerce)) { pos += group.size } else if (group.required != ParameterGroup.RequiredLevel.OPTIONAL) { return if (group.required == ParameterGroup.RequiredLevel.ERROR_IF_ABSENT) { @@ -247,6 +249,15 @@ } } + // Sugars are valid on any injector and should be ignored, as long as they're at the end. + while (pos < parameters.size) { + if (parameters[pos].isMixinExtrasSugar) { + pos++ + } else { + break + } + } + // check we have consumed all the parameters if (pos < parameters.size) { return if ( @@ -288,6 +299,11 @@ return@dropWhile fqname != MixinConstants.Classes.CALLBACK_INFO && fqname != MixinConstants.Classes.CALLBACK_INFO_RETURNABLE }.drop(1) // the first element in the list is the CallbackInfo but we don't want it + .takeWhile { !it.isMixinExtrasSugar } + + // We want to preserve sugars, and while we're at it, we might as well move them all to the end + val sugars = parameters.parameters.filter { it.isMixinExtrasSugar } + val newParams = expected.flatMapTo(mutableListOf()) { if (it.default) { it.parameters.mapIndexed { i: Int, p: Parameter -> @@ -302,8 +318,9 @@ emptyList() } } - // Restore the captured locals before applying the fix + // Restore the captured locals and sugars before applying the fix newParams.addAll(locals) + newParams.addAll(sugars) parameters.synchronize(newParams) } } Index: src/main/kotlin/platform/mixin/util/Mixin.kt =================================================================== --- src/main/kotlin/platform/mixin/util/Mixin.kt (revision 0002cf5bbe9735608bcf2bdcad66074fd1cac592) +++ src/main/kotlin/platform/mixin/util/Mixin.kt (revision 3bd5b6ddf2408a476330a818a623f03f9033973a) @@ -30,6 +30,7 @@ import com.intellij.psi.PsiDisjunctionType import com.intellij.psi.PsiElement import com.intellij.psi.PsiIntersectionType +import com.intellij.psi.PsiParameter import com.intellij.psi.PsiPrimitiveType import com.intellij.psi.PsiType import com.intellij.psi.search.GlobalSearchScope @@ -121,6 +122,11 @@ return targets.isNotEmpty() && !targets.any { it.hasAccess(Opcodes.ACC_INTERFACE) } } +val PsiParameter.isMixinExtrasSugar: Boolean + get() { + return annotations.any { it.qualifiedName?.contains(".mixinextras.sugar.") == true } + } + fun callbackInfoType(project: Project): PsiType = PsiType.getTypeByName(CALLBACK_INFO, project, GlobalSearchScope.allScope(project))