Skip to content

Commit 12e6f9c

Browse files
committed
Merge branch '2024.3' into 2025.1
2 parents 62e8d4c + 8dbe944 commit 12e6f9c

File tree

9 files changed

+188
-59
lines changed

9 files changed

+188
-59
lines changed

changelog.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,43 @@
11
# Minecraft Development for IntelliJ
22

3+
## [1.8.6]
4+
5+
## Added
6+
7+
- Debug flow diagrams for MixinExtras expressions.
8+
- An inspection to replace `INVOKE_ASSIGN` with MixinExtras expressions where possible.
9+
- Expressions are preferred because `INVOKE_ASSIGN` doesn't fail if there's no assignment.
10+
11+
## Changed
12+
13+
- Performance improvements for shadow completions.
14+
- Smarter warnings for discouraged shifting
15+
- Shifting is now always discouraged on injectors that can't inject on any instruction in the method (such as `@Redirect`).
16+
- When MixinExtras expressions are being used, the discourage shifting logic now takes into account the type of expression.
17+
- Mixin navigation to lambdas has been improved. MinecraftDev will now properly detect that a synthetic method will be
18+
generated for method references in the following additional cases:
19+
- All array method references.
20+
- Method references to a superclass method (`super::foo`).
21+
- Constructor method references for a non-static inner class.
22+
- Previously, all constructor method references were incorrectly assumed to generate a synthetic method.
23+
- Varargs parameter expansions.
24+
- Access to private methods in an outer or inner class before Java 9.
25+
- Access to protected methods in the superclass of an outer class, if the superclass is in a different package.
26+
- Cases where the functional interface method being implemented has a parameter which is an intersection type (a type
27+
parameter extending multiple things).
28+
29+
## Fixed
30+
31+
- Fixed "generate accessor/invoker" action not doing anything.
32+
- Fixed Mixin version detection in legacy/non-standard Minecraft environments. The Mixin version is now taken from the
33+
`MixinBootstrap` class, rather than attempting to decipher it from the library artifact.
34+
- Fixed `@Coerce` on return type wanting subtypes not supertypes.
35+
- Fixed the "add definition" quick-fix for MixinExtras expressions creating a "dummy" definition since 2025.1
36+
- Fixed incorrect unused warnings on MixinExtras expression definitions
37+
- Fixed "find usages" on MixinExtras expression definitions
38+
- Fixed IDE error that sometimes occurs when navigating to mixin target
39+
- Fixed mixin navigation to field assignments.
40+
341
## [1.8.5]
442

543
### Added

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ org.gradle.jvmargs=-Xmx1g
2323

2424
ideaVersionName = 2025.1
2525

26-
coreVersion = 1.8.5
26+
coreVersion = 1.8.6
2727

2828
# Silences a build-time warning because we are bundling our own kotlin library
2929
kotlin.stdlib.default.dependency = false

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fuel-coroutines = { module = "com.github.kittinunf.fuel:fuel-coroutines", versio
6060
# Testing
6161
test-mixin = "org.spongepowered:mixin:0.8.5"
6262
test-spigotapi = "org.spigotmc:spigot-api:1.21-R0.1-SNAPSHOT"
63-
test-bungeecord = "net.md-5:bungeecord-api:1.21-R0.3-SNAPSHOT"
63+
test-bungeecord = "net.md-5:bungeecord-api:1.21-R0.3"
6464
test-spongeapi = "org.spongepowered:spongeapi:7.4.0"
6565
test-fabricloader = "net.fabricmc:fabric-loader:0.15.11"
6666
test-nbt = "com.demonwav.mcdev:all-types-nbt:1.0"

src/main/kotlin/platform/mixin/expression/gui/DiagramStyles.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,29 @@ object DiagramStyles {
6464
)
6565
val FAILED
6666
get() = mapOf(
67-
mxConstants.STYLE_STROKECOLOR to JBColor.red.hexString,
67+
mxConstants.STYLE_STROKECOLOR to FlowMatchStatus.FAIL.hexColor,
6868
mxConstants.STYLE_STROKEWIDTH to "3.5",
6969
)
7070
val PARTIAL_MATCH
7171
get() = mapOf(
72-
mxConstants.STYLE_STROKECOLOR to JBColor.orange.hexString,
72+
mxConstants.STYLE_STROKECOLOR to FlowMatchStatus.PARTIAL.hexColor,
7373
mxConstants.STYLE_STROKEWIDTH to "2.5",
7474
)
7575
val SUCCESS
7676
get() = mapOf(
77-
mxConstants.STYLE_STROKECOLOR to JBColor.green.hexString,
77+
mxConstants.STYLE_STROKECOLOR to FlowMatchStatus.SUCCESS.hexColor,
7878
mxConstants.STYLE_STROKEWIDTH to "1.5",
7979
)
8080
val CURRENT_EDITOR_FONT
8181
get() = EditorColorsManager.getInstance().globalScheme.getFont(EditorFontType.PLAIN)
8282
}
8383

84-
private val Color.hexString get() = "#%06X".format(rgb)
84+
private val Color.hexString get() = "#%06X".format(rgb and 0xFFFFFF)
85+
86+
val FlowMatchStatus.hexColor
87+
get() = when (this) {
88+
FlowMatchStatus.SUCCESS -> JBColor.green
89+
FlowMatchStatus.PARTIAL -> JBColor.orange
90+
FlowMatchStatus.FAIL -> JBColor.red
91+
FlowMatchStatus.IGNORED -> UIUtil.getLabelForeground()
92+
}.hexString

src/main/kotlin/platform/mixin/expression/gui/FlowDiagram.kt

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ package com.demonwav.mcdev.platform.mixin.expression.gui
2222

2323
import com.demonwav.mcdev.platform.mixin.expression.MEExpressionMatchUtil
2424
import com.demonwav.mcdev.util.constantStringValue
25-
import com.intellij.openapi.application.ApplicationManager
2625
import com.intellij.openapi.application.EDT
27-
import com.intellij.openapi.application.ModalityState
28-
import com.intellij.openapi.application.ReadAction
26+
import com.intellij.openapi.application.readAction
2927
import com.intellij.openapi.module.Module
3028
import com.intellij.openapi.progress.checkCanceled
3129
import com.intellij.openapi.project.Project
@@ -41,8 +39,9 @@ import com.mxgraph.util.mxRectangle
4139
import com.mxgraph.view.mxGraph
4240
import java.awt.Dimension
4341
import java.util.SortedMap
44-
import java.util.concurrent.Callable
42+
import kotlinx.coroutines.CoroutineScope
4543
import kotlinx.coroutines.Dispatchers
44+
import kotlinx.coroutines.launch
4645
import kotlinx.coroutines.withContext
4746
import org.objectweb.asm.tree.ClassNode
4847
import org.objectweb.asm.tree.MethodNode
@@ -53,15 +52,21 @@ private const val INTRA_GROUP_SPACING = 75
5352
private const val LINE_NUMBER_STYLE = "LINE_NUMBER"
5453

5554
class FlowDiagram(
55+
private val scope: CoroutineScope,
5656
val ui: FlowDiagramUi,
5757
private val flowGraph: FlowGraph,
5858
private val clazz: ClassNode,
5959
val method: MethodNode,
6060
) {
6161
companion object {
62-
suspend fun create(project: Project, clazz: ClassNode, method: MethodNode): FlowDiagram? {
62+
suspend fun create(
63+
project: Project,
64+
scope: CoroutineScope,
65+
clazz: ClassNode,
66+
method: MethodNode
67+
): FlowDiagram? {
6368
val flowGraph = FlowGraph.parse(project, clazz, method) ?: return null
64-
return buildDiagram(flowGraph, clazz, method)
69+
return buildDiagram(scope, flowGraph, clazz, method)
6570
}
6671
}
6772

@@ -91,6 +96,12 @@ class FlowDiagram(
9196
flowGraph.highlightMatches(node, soft)
9297
ui.refresh()
9398
}
99+
100+
flowGraph.onHighlightChanged { exprText, node ->
101+
scope.launch(Dispatchers.EDT) {
102+
ui.showExpr(exprText, node)
103+
}
104+
}
94105
}
95106

96107
fun populateMatchStatuses(
@@ -105,41 +116,42 @@ class FlowDiagram(
105116
val oldHighlightRoot = flowGraph.highlightRoot
106117
ui.setMatchToolbarVisible(false)
107118
flowGraph.resetMatches()
108-
ReadAction.nonBlocking(Callable<String?> run@{
109-
val stringLit = stringRef.element ?: return@run null
110-
val modifierList = modifierListRef.element ?: return@run null
111-
val expression = stringLit.constantStringValue?.let(MEExpressionMatchUtil::createExpression)
112-
?: return@run null
113-
val pool = MEExpressionMatchUtil.createIdentifierPoolFactory(module, clazz, modifierList)(method)
114-
for ((virtualInsn, root) in flowGraph.flowMap) {
115-
val node = flowGraph.allNodes.getValue(root)
116-
MEExpressionMatchUtil.findMatchingInstructions(
117-
clazz, method, pool, flowGraph.flowMap, expression, listOf(virtualInsn),
118-
ExpressionContext.Type.MODIFY_EXPRESSION_VALUE, // most permissive
119-
false,
120-
node::reportMatchStatus,
121-
node::reportPartialMatch
122-
) {}
119+
scope.launch(Dispatchers.Default) {
120+
val success = readAction run@{
121+
val stringLit = stringRef.element ?: return@run false
122+
val modifierList = modifierListRef.element ?: return@run false
123+
val expression = stringLit.constantStringValue?.let(MEExpressionMatchUtil::createExpression)
124+
?: return@run false
125+
val pool = MEExpressionMatchUtil.createIdentifierPoolFactory(module, clazz, modifierList)(method)
126+
for ((virtualInsn, root) in flowGraph.flowMap) {
127+
val node = flowGraph.allNodes.getValue(root)
128+
MEExpressionMatchUtil.findMatchingInstructions(
129+
clazz, method, pool, flowGraph.flowMap, expression, listOf(virtualInsn),
130+
ExpressionContext.Type.MODIFY_EXPRESSION_VALUE, // most permissive
131+
false,
132+
node::reportMatchStatus,
133+
node::reportPartialMatch
134+
) {}
135+
}
136+
flowGraph.setExprText(expression.src.toString())
137+
flowGraph.highlightMatches(oldHighlightRoot, false)
138+
true
123139
}
124-
flowGraph.markHasMatchData()
125-
flowGraph.highlightMatches(oldHighlightRoot, false)
126-
StringUtil.escapeStringCharacters(expression.src.toString())
127-
})
128-
.finishOnUiThread(ModalityState.nonModal()) { exprText ->
129-
exprText ?: return@finishOnUiThread
140+
if (success) {
130141
if (jump) {
131142
showBestNode()
132143
}
133-
ui.refresh()
134-
ui.setExprText(exprText)
135144
}
136-
.submit(ApplicationManager.getApplication()::executeOnPooledThread)
145+
ui.refresh()
146+
}
137147
}
138148
this.jumpToExpression = {
139-
ReadAction.run<Nothing> {
140-
val target = stringRef.element
141-
if (target is Navigatable && target.isValid && target.canNavigate()) {
142-
target.navigate(true)
149+
scope.launch {
150+
readAction {
151+
val target = stringRef.element
152+
if (target is Navigatable && target.isValid && target.canNavigate()) {
153+
target.navigate(true)
154+
}
143155
}
144156
}
145157
}
@@ -161,7 +173,12 @@ class FlowDiagram(
161173
}
162174
}
163175

164-
private suspend fun buildDiagram(flowGraph: FlowGraph, clazz: ClassNode, method: MethodNode): FlowDiagram {
176+
private suspend fun buildDiagram(
177+
scope: CoroutineScope,
178+
flowGraph: FlowGraph,
179+
clazz: ClassNode,
180+
method: MethodNode
181+
): FlowDiagram {
165182
val graph = MxFlowGraph(flowGraph)
166183
setupStyles(graph)
167184
val groupedCells = addGraphContent(graph, flowGraph)
@@ -171,7 +188,7 @@ private suspend fun buildDiagram(flowGraph: FlowGraph, clazz: ClassNode, method:
171188
val ui = withContext(Dispatchers.EDT) {
172189
FlowDiagramUi(graph, calculateBounds, lineNumberNodes)
173190
}
174-
return FlowDiagram(ui, flowGraph, clazz, method)
191+
return FlowDiagram(scope, ui, flowGraph, clazz, method)
175192
}
176193

177194
private class MxFlowGraph(private val flowGraph: FlowGraph) : mxGraph() {

src/main/kotlin/platform/mixin/expression/gui/FlowDiagramUi.kt

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package com.demonwav.mcdev.platform.mixin.expression.gui
2222

2323
import com.intellij.icons.AllIcons
2424
import com.intellij.openapi.editor.colors.EditorColorsManager
25+
import com.intellij.openapi.util.text.StringUtil
2526
import com.intellij.ui.DocumentAdapter
2627
import com.mxgraph.model.mxCell
2728
import com.mxgraph.swing.mxGraphComponent
@@ -83,8 +84,8 @@ class FlowDiagramUi(
8384
fixBounds()
8485
}
8586

86-
fun setExprText(text: String) {
87-
matchToolbar.setExprTest(text)
87+
fun showExpr(text: String, highlightRoot: FlowNode?) {
88+
matchToolbar.setExprText("<html>" + makeExprString(text, highlightRoot) + "</html>")
8889
matchToolbar.isVisible = true
8990
}
9091

@@ -243,7 +244,7 @@ class FlowDiagramUi(
243244
add(buttonPanel, BorderLayout.EAST)
244245
}
245246

246-
fun setExprTest(text: String) {
247+
fun setExprText(text: String) {
247248
exprText.text = text
248249
exprText.toolTipText = text
249250
}
@@ -277,3 +278,54 @@ private fun makeButton(icon: Icon, tooltip: String): JButton =
277278
toolTipText = tooltip
278279
preferredSize = Dimension(32, 32)
279280
}
281+
282+
private sealed class HighlightChange : Comparable<HighlightChange> {
283+
abstract val pos: Int
284+
285+
data class Start(override val pos: Int, val length: Int, val status: FlowMatchStatus) : HighlightChange()
286+
data class End(override val pos: Int) : HighlightChange()
287+
288+
override fun compareTo(other: HighlightChange): Int =
289+
compareValuesBy(
290+
this, other,
291+
{ it.pos },
292+
{ if (it is Start) 1 else -1 },
293+
{ -((it as? Start)?.length ?: 0) },
294+
)
295+
}
296+
297+
private fun makeExprString(text: String, highlightRoot: FlowNode?): String {
298+
fun escape(str: String) = StringUtil.escapeXmlEntities(StringUtil.escapeStringCharacters(str))
299+
300+
if (highlightRoot == null) {
301+
return escape(text)
302+
}
303+
304+
val changes = mutableListOf<HighlightChange>()
305+
for ((status, src) in highlightRoot.matches) {
306+
if (src == null) {
307+
continue
308+
}
309+
changes.add(HighlightChange.Start(src.startIndex, src.endIndex - src.startIndex, status))
310+
changes.add(HighlightChange.End(src.endIndex + 1))
311+
}
312+
changes.sort()
313+
314+
val result = StringBuilder()
315+
var pos = 0
316+
for (change in changes) {
317+
result.append(escape(text.substring(pos, change.pos)))
318+
pos = change.pos
319+
when (change) {
320+
is HighlightChange.Start -> {
321+
result.append("<span style='color: ${change.status.hexColor}'>")
322+
}
323+
is HighlightChange.End -> {
324+
result.append("</span>")
325+
}
326+
}
327+
}
328+
result.append(escape(text.substring(pos)))
329+
330+
return result.toString()
331+
}

0 commit comments

Comments
 (0)