Skip to content

Commit

Permalink
Merge branch '2023.2' into 2023.3
Browse files Browse the repository at this point in the history
  • Loading branch information
RedNesto committed Dec 16, 2023
2 parents 5855f63 + ecb059b commit b1fe6c4
Show file tree
Hide file tree
Showing 21 changed files with 278 additions and 36 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ kotlin.code.style=official
ideaVersion = 2023.3
ideaVersionName = 2023.3

coreVersion = 1.6.11
coreVersion = 1.6.12
downloadIdeaSources = true

pluginTomlVersion = 233.11799.172
Expand Down
6 changes: 1 addition & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ Minecraft Development for IntelliJ
<td align="right"><b>Main Build</b></td>
<td colspan="2"><a href="https://ci.mcdev.io/viewType.html?buildTypeId=MinecraftDev_Build"><img src="https://ci.mcdev.io/app/rest/builds/buildType:(id:MinecraftDev_Build)/statusIcon.svg" alt="Teamcity Build Status" /></a></td>
</tr>
<tr>
<td align="left">2022.3</td>
<td align="left"><a href="https://ci.mcdev.io/viewType.html?buildTypeId=MinecraftDev_Nightly_20223"><img src="https://ci.mcdev.io/app/rest/builds/buildType:(id:MinecraftDev_Nightly_20223)/statusIcon.svg" alt="2022.3 Nightly Status" /></a></td>
</tr>
<tr>
<td align="left">2023.1</td>
<td align="left"><a href="https://ci.mcdev.io/viewType.html?buildTypeId=MinecraftDev_Nightly_20231"><img src="https://ci.mcdev.io/app/rest/builds/buildType:(id:MinecraftDev_Nightly_20231)/statusIcon.svg" alt="2023.1 Nightly Status" /></a></td>
Expand All @@ -35,7 +31,7 @@ Minecraft Development for IntelliJ
</tr>
</table>

Info and Documentation [![Current Release](https://img.shields.io/badge/release-1.6.11-orange.svg?style=flat-square)](https://plugins.jetbrains.com/plugin/8327)
Info and Documentation [![Current Release](https://img.shields.io/badge/release-1.6.12-orange.svg?style=flat-square)](https://plugins.jetbrains.com/plugin/8327)
----------------------

<a href="https://discord.gg/j6UNcfr"><img src="https://i.imgur.com/JXu9C1G.png" height="48px"></img></a>
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/MinecraftConfigurable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ class MinecraftConfigurable : Configurable {
settings.isShowEventListenerGutterIcons = showEventListenerGutterCheckBox.isSelected
settings.isShowChatColorGutterIcons = showChatGutterIconsCheckBox.isSelected
settings.isShowChatColorUnderlines = showChatColorUnderlinesCheckBox.isSelected
settings.underlineType = chatColorUnderlinesComboBox.selectedItem as MinecraftSettings.UnderlineType
settings.underlineType = chatColorUnderlinesComboBox.selectedItem as? MinecraftSettings.UnderlineType
?: MinecraftSettings.UnderlineType.DOTTED
}

override fun reset() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@

package com.demonwav.mcdev.insight.generation

import com.demonwav.mcdev.asset.MCDevBundle
import com.intellij.codeInsight.generation.actions.BaseGenerateAction
import com.intellij.openapi.actionSystem.AnActionEvent

class GenerateEventListenerAction : BaseGenerateAction(GenerateEventListenerHandler())
class GenerateEventListenerAction : BaseGenerateAction(GenerateEventListenerHandler()) {

override fun update(e: AnActionEvent) {
super.update(e)
e.presentation.text = MCDevBundle("generate.event_listener.title")
}
}
8 changes: 7 additions & 1 deletion src/main/kotlin/platform/bukkit/creator/bukkit-platforms.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import com.demonwav.mcdev.platform.PlatformType
import com.demonwav.mcdev.util.MinecraftTemplates
import com.demonwav.mcdev.util.MinecraftVersions
import com.demonwav.mcdev.util.SemanticVersion
import com.intellij.icons.AllIcons
import com.intellij.openapi.observable.util.bindBooleanStorage
import com.intellij.openapi.ui.validation.WHEN_GRAPH_PROPAGATION_FINISHED
import com.intellij.ui.content.AlertIcon
import com.intellij.ui.dsl.builder.Panel
import com.intellij.ui.dsl.builder.bindSelected

Expand Down Expand Up @@ -74,7 +76,11 @@ class PaperPlatformStep(parent: BukkitPlatformStep) : AbstractBukkitPlatformStep
override fun setupUI(builder: Panel) {
super.setupUI(builder)
with(builder) {
row("Paper manifest:") {
row("Paper Manifest:") {
icon(AlertIcon(AllIcons.General.Warning)).comment(
"Paper plugins are <a href=\"https://docs.papermc.io/paper/dev/getting-started/paper-plugins\">" +
"still experimental</a>, their usage is discouraged for general purpose development. "
)
checkBox("Use paper-plugin.yml")
.bindSelected(usePaperManifestProperty)
.validationRequestor(WHEN_GRAPH_PROPAGATION_FINISHED(propertyGraph))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,10 @@ class GenerateOverwriteAction : MixinCodeInsightAction() {
return
}

// Generate needed shadows
val newShadows = createShadowMembers(project, psiClass, filterNewShadows(requiredMembers, psiClass))

disableAnnotationWrapping(project) {
runWriteAction {
// Generate needed shadows
val newShadows = createShadowMembers(project, psiClass, filterNewShadows(requiredMembers, psiClass))
// Insert shadows
insertShadows(psiClass, newShadows)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.MethodInsnNode
import org.objectweb.asm.tree.MethodNode

class MethodInjectionPoint : AbstractMethodInjectionPoint() {
abstract class AbstractInvokeInjectionPoint(private val assign: Boolean) : AbstractMethodInjectionPoint() {
override fun createNavigationVisitor(
at: PsiAnnotation,
target: MixinSelector?,
Expand All @@ -53,9 +53,9 @@ class MethodInjectionPoint : AbstractMethodInjectionPoint() {
mode: CollectVisitor.Mode,
): CollectVisitor<PsiMethod>? {
if (mode == CollectVisitor.Mode.COMPLETION) {
return MyCollectVisitor(mode, at.project, MemberReference(""))
return MyCollectVisitor(mode, at.project, MemberReference(""), assign)
}
return target?.let { MyCollectVisitor(mode, at.project, it) }
return target?.let { MyCollectVisitor(mode, at.project, it, assign) }
}

private class MyNavigationVisitor(
Expand Down Expand Up @@ -141,6 +141,7 @@ class MethodInjectionPoint : AbstractMethodInjectionPoint() {
mode: Mode,
private val project: Project,
private val selector: MixinSelector,
private val assign: Boolean,
) : CollectVisitor<PsiMethod>(mode) {
override fun accept(methodNode: MethodNode) {
val insns = methodNode.instructions ?: return
Expand All @@ -150,12 +151,19 @@ class MethodInjectionPoint : AbstractMethodInjectionPoint() {
}

val sourceMethod = nodeMatchesSelector(insn, mode, selector, project) ?: return@forEachRemaining
addResult(
insn,
sourceMethod,
qualifier = insn.owner.replace('/', '.'),
)
val actualInsn = if (assign) insn.next else insn
if (actualInsn != null) {
addResult(
actualInsn,
sourceMethod,
qualifier = insn.owner.replace('/', '.'),
)
}
}
}
}
}

class InvokeInjectionPoint : AbstractInvokeInjectionPoint(false)

class InvokeAssignInjectionPoint : AbstractInvokeInjectionPoint(true)
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ abstract class MixinExtrasInjectorAnnotationHandler : InjectorAnnotationHandler(
.resolveAsm(annotation.project) as? MethodTargetMember
)?.classAndMethod
sourceClassAndMethod?.method?.getGenericReturnType(sourceClassAndMethod.clazz, annotation.project)
?: Type.getType(insn.desc).toPsiType(elementFactory)
?: Type.getReturnType(insn.desc).toPsiType(elementFactory)
}

is FieldInsnNode -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiNameHelper
import com.intellij.psi.PsiParameterList
import com.intellij.psi.PsiPrimitiveType
import com.intellij.psi.PsiType
import com.intellij.psi.codeStyle.JavaCodeStyleManager
import com.intellij.psi.codeStyle.VariableKind
import com.intellij.psi.util.PsiUtil
import com.intellij.psi.util.TypeConversionUtil
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.AbstractInsnNode
Expand Down Expand Up @@ -318,13 +320,15 @@ class InvalidInjectorMethodSignatureInspection : MixinInspection() {

val newParams = expected.flatMapTo(mutableListOf()) {
if (it.default) {
val nameHelper = PsiNameHelper.getInstance(project)
val languageLevel = PsiUtil.getLanguageLevel(parameters)
it.parameters.mapIndexed { i: Int, p: Parameter ->
JavaPsiFacade.getElementFactory(project).createParameter(
p.name ?: JavaCodeStyleManager.getInstance(project)
val paramName = p.name?.takeIf { name -> nameHelper.isIdentifier(name, languageLevel) }
?: JavaCodeStyleManager.getInstance(project)
.suggestVariableName(VariableKind.PARAMETER, null, null, p.type).names
.firstOrNull() ?: "var$i",
p.type,
)
.firstOrNull()
?: "var$i"
JavaPsiFacade.getElementFactory(project).createParameter(paramName, p.type)
}
} else {
emptyList()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/*
* Minecraft Development for IntelliJ
*
* https://mcdev.io/
*
* Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
*/

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.handlers.mixinextras.WrapOperationHandler
import com.demonwav.mcdev.platform.mixin.inspection.MixinInspection
import com.demonwav.mcdev.platform.mixin.util.MixinConstants
import com.demonwav.mcdev.util.findContainingMethod
import com.intellij.codeInspection.LocalQuickFixOnPsiElement
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementFactory
import com.intellij.psi.PsiExpressionList
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiParameter
import com.intellij.psi.PsiReferenceExpression
import com.intellij.psi.PsiType
import com.intellij.psi.PsiTypes
import com.intellij.psi.search.searches.OverridingMethodsSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiUtil
import com.intellij.psi.util.parentOfType
import com.siyeh.ig.psiutils.MethodCallUtils
import org.jetbrains.plugins.groovy.intentions.style.inference.resolve

class UnnecessaryMutableLocalInspection : MixinInspection() {
override fun getStaticDescription() = "Unnecessary mutable reference to captured local"

override fun buildVisitor(holder: ProblemsHolder) = object : JavaElementVisitor() {
override fun visitMethod(method: PsiMethod) {
val project = method.project
val hasValidMixinAnnotation = method.annotations.any { ann ->
ann.qualifiedName?.let { MixinAnnotationHandler.forMixinAnnotation(it, project) }
// Mutable Local references do have different semantics inside a WrapOperation.
?.let { it is InjectorAnnotationHandler && it !is WrapOperationHandler } == true
}
if (!hasValidMixinAnnotation) {
return
}

// ignore if method has any references
val hasReferences = ReferencesSearch.search(method)
.mapNotNull { PsiUtil.skipParenthesizedExprUp(it.element).parent as? PsiMethodCallExpression }
.any { !MethodCallUtils.hasSuperQualifier(it) }
if (hasReferences) {
return
}

for ((i, param) in method.parameterList.parameters.withIndex()) {
if (!param.hasAnnotation(MixinConstants.MixinExtras.LOCAL)) {
continue
}
val paramType = param.type.resolve()
if (paramType?.qualifiedName?.startsWith(MixinConstants.MixinExtras.LOCAL_REF_PACKAGE) != true) {
continue
}

checkParameter(holder, method, param, i, paramType)
}
}
}

private fun checkParameter(
holder: ProblemsHolder,
originalMethod: PsiMethod,
originalParam: PsiParameter,
paramIndex: Int,
paramType: PsiClass
) {
var hasAnyGets = false
for (method in OverridingMethodsSearch.search(originalMethod).findAll() + listOf(originalMethod)) {
val param = method.parameterList.getParameter(paramIndex) ?: return
val getMethod = paramType.findMethodsByName("get", false).firstOrNull() ?: return
for (ref in ReferencesSearch.search(param)) {
if (isDelegationToSuper(ref.element, paramIndex)) {
continue
}
val parent = PsiUtil.skipParenthesizedExprUp(ref.element.parent) as? PsiReferenceExpression ?: return
if (parent.references.any { it.isReferenceTo(getMethod) }) {
hasAnyGets = true
} else {
return
}
}
}
if (!hasAnyGets) {
// Don't annoy them if they've just made the parameter
return
}
holder.registerProblem(
originalParam.typeElement ?: originalParam,
"@Local could be captured immutably",
SwitchToImmutableCaptureFix(originalParam)
)
}

// Ignore super delegations in subclasses. super.foo(myLocalRef) has no effect on whether the local can be converted
private fun isDelegationToSuper(ref: PsiElement, paramIndex: Int): Boolean {
val method = ref.findContainingMethod() ?: return false
val superMethod = method.findSuperMethods().firstOrNull { it.containingClass?.isInterface == false }
?: return false

// For some reason ref is sometimes the identifier rather than the reference expression. Get the reference expr
val actualRef = if (ref is PsiReferenceExpression) {
ref
} else {
PsiUtil.skipParenthesizedExprUp(ref.parent) as? PsiReferenceExpression ?: return false
}
val param = PsiUtil.skipParenthesizedExprUp(actualRef)
val paramList = param.parent as? PsiExpressionList ?: return false
val methodCall = paramList.parent as? PsiMethodCallExpression ?: return false

// Check that the method call is a super call
if (!MethodCallUtils.hasSuperQualifier(methodCall)) {
return false
}

// Check that our reference is in the correct parameter index
if (paramList.expressions.getOrNull(paramIndex) != param) {
return false
}

// Check that the super call is referencing the correct super method.
return methodCall.resolveMethod() == superMethod
}

private class SwitchToImmutableCaptureFix(param: PsiParameter) : LocalQuickFixOnPsiElement(param) {
override fun getFamilyName() = "Switch to immutable capture"
override fun getText() = "Switch to immutable capture"

override fun invoke(project: Project, file: PsiFile, startElement: PsiElement, endElement: PsiElement) {
val param = startElement as? PsiParameter ?: return
val method = param.parentOfType<PsiMethod>() ?: return
val paramIndex = method.parameterList.getParameterIndex(param)
val methods = mutableListOf(method)
if (file.isPhysical) {
methods.addAll(OverridingMethodsSearch.search(method))
}
for (impl in methods) {
fixMethod(impl, paramIndex)
}
}

private fun fixMethod(method: PsiMethod, paramIndex: Int) {
val param = method.parameterList.getParameter(paramIndex) ?: return
val paramType = param.type as? PsiClassType ?: return
val innerType = paramType.innerRefType ?: return
val factory = PsiElementFactory.getInstance(method.project)
param.typeElement?.replace(factory.createTypeElement(innerType))
for (ref in ReferencesSearch.search(param)) {
val refExpression = PsiUtil.skipParenthesizedExprUp(ref.element.parent) as? PsiReferenceExpression
?: continue
val call = refExpression.parent as? PsiMethodCallExpression ?: continue
call.replace(ref.element)
}
}

private val PsiClassType.innerRefType: PsiType?
get() =
when (resolve()?.qualifiedName?.substringAfterLast('.')) {
"LocalBooleanRef" -> PsiTypes.booleanType()
"LocalCharRef" -> PsiTypes.charType()
"LocalDoubleRef" -> PsiTypes.doubleType()
"LocalFloatRef" -> PsiTypes.floatType()
"LocalIntRef" -> PsiTypes.intType()
"LocalLongRef" -> PsiTypes.longType()
"LocalShortRef" -> PsiTypes.shortType()
"LocalRef" -> parameters.getOrNull(0)
else -> null
}
}
}
Loading

0 comments on commit b1fe6c4

Please sign in to comment.