-
Notifications
You must be signed in to change notification settings - Fork 197
[WIP] Add specialized MCP color support #459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
marvin-roesch
wants to merge
3
commits into
dev
Choose a base branch
from
feature/mcp-colors
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,133
−3
Draft
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/McpColorAnnotator.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color | ||
|
||
import com.demonwav.mcdev.MinecraftSettings | ||
import com.demonwav.mcdev.insight.ColorAnnotator | ||
import com.intellij.lang.annotation.AnnotationHolder | ||
import com.intellij.lang.annotation.Annotator | ||
import com.intellij.psi.PsiElement | ||
|
||
class McpColorAnnotator : Annotator { | ||
|
||
override fun annotate(element: PsiElement, holder: AnnotationHolder) { | ||
if (!MinecraftSettings.instance.isShowChatColorUnderlines) { | ||
return | ||
} | ||
|
||
for (call in element.findColors()) { | ||
ColorAnnotator.setColorAnnotator(call.arg, element, holder) | ||
} | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/McpColorLineMarkerProvider.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color | ||
|
||
import com.intellij.codeHighlighting.Pass | ||
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler | ||
import com.intellij.codeInsight.daemon.LineMarkerInfo | ||
import com.intellij.codeInsight.daemon.LineMarkerProvider | ||
import com.intellij.codeInsight.daemon.MergeableLineMarkerInfo | ||
import com.intellij.codeInsight.daemon.NavigateAction | ||
import com.intellij.icons.AllIcons | ||
import com.intellij.openapi.editor.markup.GutterIconRenderer | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.util.PsiUtilBase | ||
import com.intellij.ui.ColorChooser | ||
import com.intellij.util.Function | ||
import com.intellij.util.ui.ColorIcon | ||
import com.intellij.util.ui.TwoColorsIcon | ||
import java.awt.Color | ||
import javax.swing.Icon | ||
|
||
class McpColorLineMarkerProvider : LineMarkerProvider { | ||
override fun getLineMarkerInfo(element: PsiElement) = null | ||
|
||
override fun collectSlowLineMarkers(elements: List<PsiElement>, result: MutableCollection<LineMarkerInfo<PsiElement>>) { | ||
for (element in elements) { | ||
val calls = element.findColors() | ||
|
||
for (call in calls) { | ||
val info = McpColorInfo(element, call) | ||
NavigateAction.setNavigateAction(info, "Change color", null) | ||
result.add(info) | ||
} | ||
} | ||
} | ||
|
||
private class McpColorInfo(private val parent: PsiElement, private val result: McpColorResult<Color>) : MergeableLineMarkerInfo<PsiElement>( | ||
result.expression, | ||
result.argRange, | ||
ColorIcon(12, result.arg), | ||
Pass.UPDATE_ALL, | ||
Function { result.param.description }, | ||
GutterIconNavigationHandler handler@{ _, _ -> | ||
if (!result.expression.isWritable) { | ||
return@handler | ||
} | ||
|
||
val editor = PsiUtilBase.findEditor(result.expression) ?: return@handler | ||
|
||
val c = ColorChooser.chooseColor(editor.component, "Choose ${result.param.description}", result.arg, result.param.hasAlpha) | ||
if (c != null) { | ||
result.param.setColor(result.withArg(c)) | ||
} | ||
}, | ||
GutterIconRenderer.Alignment.RIGHT | ||
) { | ||
override fun canMergeWith(info: MergeableLineMarkerInfo<*>) = info is McpColorInfo && info.parent == parent | ||
override fun getCommonIconAlignment(infos: List<MergeableLineMarkerInfo<*>>) = GutterIconRenderer.Alignment.RIGHT | ||
|
||
override fun getCommonIcon(infos: List<MergeableLineMarkerInfo<*>>): Icon { | ||
if (infos.size == 2 && infos[0] is McpColorInfo && infos[1] is McpColorInfo) { | ||
return TwoColorsIcon(12, (infos[0] as McpColorInfo).result.arg, (infos[1] as McpColorInfo).result.arg) | ||
} | ||
return AllIcons.Gutter.Colors | ||
} | ||
|
||
override fun getElementPresentation(element: PsiElement): String { | ||
return result.param.description | ||
} | ||
} | ||
} |
334 changes: 334 additions & 0 deletions
334
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/McpColorMethod.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color | ||
|
||
import com.demonwav.mcdev.facet.MinecraftFacet | ||
import com.demonwav.mcdev.insight.setColor | ||
import com.demonwav.mcdev.platform.mcp.McpModuleType | ||
import com.demonwav.mcdev.platform.mcp.srg.SrgManager | ||
import com.demonwav.mcdev.util.MemberReference | ||
import com.demonwav.mcdev.util.findModule | ||
import com.demonwav.mcdev.util.referencedMethod | ||
import com.demonwav.mcdev.util.runWriteAction | ||
import com.google.gson.JsonDeserializationContext | ||
import com.google.gson.JsonDeserializer | ||
import com.google.gson.JsonElement | ||
import com.intellij.psi.JavaPsiFacade | ||
import com.intellij.psi.PsiCall | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiLiteralExpression | ||
import com.intellij.psi.PsiMethod | ||
import java.awt.Color | ||
import java.lang.reflect.Type | ||
|
||
data class McpColorMethod(val member: MemberReference, val srgName: Boolean, val params: List<Param>) { | ||
fun match(call: PsiCall): Boolean { | ||
val referenced = call.referencedMethod | ||
return referenced != null && referenced == getMethod(call) | ||
} | ||
|
||
fun extractColors(call: PsiCall): List<McpColorResult<Color>> { | ||
return params.mapNotNull { it.extractColor(call) } | ||
} | ||
|
||
fun validateCall(call: PsiCall): List<McpColorResult<McpColorWarning>> { | ||
if (!match(call)) { | ||
return listOf() | ||
} | ||
return params.flatMap { it.validateCall(call) } | ||
} | ||
|
||
private fun getMethod(context: PsiElement): PsiMethod? { | ||
var reference = member | ||
if (srgName) { | ||
val moduleSrgManager = context.findModule()?.let { MinecraftFacet.getInstance(it, McpModuleType)?.srgManager } | ||
val srgManager = moduleSrgManager ?: SrgManager.findAnyInstance(context.project) | ||
srgManager?.srgMapNow?.mapToMcpMethod(member)?.let { | ||
reference = it | ||
} | ||
} | ||
return reference.resolveMember(context.project) as? PsiMethod | ||
} | ||
|
||
interface Param { | ||
val description: String | ||
val hasAlpha: Boolean | ||
|
||
fun extractColor(call: PsiCall): McpColorResult<Color>? | ||
|
||
fun extractColor(result: McpColorResult<Any>): Color? | ||
|
||
fun validateCall(call: PsiCall): List<McpColorResult<McpColorWarning>> | ||
|
||
fun setColor(context: McpColorResult<Color>) | ||
} | ||
|
||
data class SingleIntParam(val position: Int, override val description: String, override val hasAlpha: Boolean) : Param { | ||
override fun extractColor(call: PsiCall): McpColorResult<Color>? { | ||
val args = call.argumentList ?: return null | ||
val colorArg = args.expressions.getOrNull(position) as? PsiLiteralExpression ?: return null | ||
val color = extractColor(colorArg) ?: return null | ||
|
||
return McpColorResult(colorArg, this, color) | ||
} | ||
|
||
override fun extractColor(result: McpColorResult<Any>): Color? { | ||
return (result.expression as? PsiLiteralExpression)?.let { extractColor(it) } | ||
} | ||
|
||
private fun extractColor(literal: PsiLiteralExpression): Color? { | ||
return Color(literal.value as? Int ?: return null, hasAlpha) | ||
} | ||
|
||
override fun validateCall(call: PsiCall): List<McpColorResult<McpColorWarning>> { | ||
val args = call.argumentList ?: return emptyList() | ||
val colorArg = args.expressions.getOrNull(position) as? PsiLiteralExpression ?: return emptyList() | ||
val literal = colorArg.text | ||
|
||
if (!literal.startsWith("0x")) { | ||
return listOf(McpColorResult(colorArg, this, McpColorWarning.NoHex)) | ||
} | ||
|
||
if (hasAlpha && literal.length in 7..8) { | ||
return listOf(McpColorResult(colorArg, this, McpColorWarning.MissingAlpha)) | ||
} | ||
|
||
if (literal.length <= 6) { | ||
return listOf(McpColorResult( | ||
colorArg, | ||
this, | ||
McpColorWarning.MissingComponents( | ||
if (literal.length > 4) listOf("red") else listOf("red", "green") | ||
) | ||
) | ||
) | ||
} | ||
|
||
if (!hasAlpha && literal.length >= 9) { | ||
return listOf(McpColorResult(colorArg, this, McpColorWarning.SuperfluousAlpha)) | ||
} | ||
|
||
return emptyList() | ||
} | ||
|
||
override fun setColor(context: McpColorResult<Color>) { | ||
val literal = context.expression as? PsiLiteralExpression ?: return | ||
literal.setColor(context.arg.rgb, hasAlpha) | ||
} | ||
|
||
object Deserializer : JsonDeserializer<SingleIntParam> { | ||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): SingleIntParam { | ||
val obj = json.asJsonObject | ||
return SingleIntParam( | ||
obj["position"]?.asInt ?: 0, | ||
obj["description"]?.asString ?: "Color", | ||
obj["hasAlpha"]?.asBoolean ?: true | ||
) | ||
} | ||
} | ||
} | ||
|
||
data class FloatVectorParam(val startPosition: Int, override val description: String, override val hasAlpha: Boolean) : Param { | ||
val length = if (hasAlpha) 4 else 3 | ||
val endIndexExclusive = startPosition + length | ||
|
||
override fun extractColor(call: PsiCall): McpColorResult<Color>? { | ||
if (validateCall(call).isNotEmpty()) { | ||
return null | ||
} | ||
|
||
val args = call.argumentList ?: return null | ||
val colorArgs = args.expressions.toList().subList(startPosition, endIndexExclusive) | ||
val components = colorArgs.mapNotNull { evaluate(it) } | ||
if (components.size < length) { | ||
return null | ||
} | ||
val r = components[0] | ||
val g = components[1] | ||
val b = components[2] | ||
val a = components.getOrNull(3) ?: 1f | ||
|
||
return McpColorResult(call, this, Color(r, g, b, a), colorArgs[0].textRange.union(colorArgs[length - 1].textRange)) | ||
} | ||
|
||
private fun evaluate(element: PsiElement): Float? { | ||
val facade = JavaPsiFacade.getInstance(element.project) | ||
return facade.constantEvaluationHelper.computeConstantExpression(element) as? Float | ||
} | ||
|
||
override fun extractColor(result: McpColorResult<Any>): Color? { | ||
val call = result.expression as? PsiCall ?: return null | ||
return extractColor(call)?.arg | ||
} | ||
|
||
override fun validateCall(call: PsiCall): List<McpColorResult<McpColorWarning>> { | ||
val args = call.argumentList ?: return emptyList() | ||
val colorArgs = args.expressions.toList().subList(startPosition, endIndexExclusive) | ||
val components = colorArgs.mapNotNull(::evaluate) | ||
if (components.size < length) { | ||
return emptyList() | ||
} | ||
|
||
val outOfRange = components.withIndex() | ||
.filter { it.value !in 0f..1f } | ||
.map { | ||
McpColorResult( | ||
colorArgs[it.index], | ||
this, | ||
McpColorWarning.ComponentOutOfRange("0.0f", "1.0f") { _ -> | ||
val literal = colorArgs[it.index] | ||
literal.containingFile.runWriteAction { | ||
val node = literal.node | ||
|
||
val literalExpression = JavaPsiFacade.getElementFactory(literal.project) | ||
.createExpressionFromText(it.value.coerceIn(0f, 1f).format(), null) as PsiLiteralExpression | ||
|
||
node.psi.replace(literalExpression) | ||
} | ||
} | ||
) | ||
}.toList() | ||
|
||
return outOfRange | ||
} | ||
|
||
override fun setColor(context: McpColorResult<Color>) { | ||
val call = context.expression as? PsiCall ?: return | ||
val expressions = call.argumentList ?: return | ||
|
||
val color = context.arg | ||
val components = arrayOf(color.red, color.green, color.blue, color.alpha) | ||
|
||
expressions.containingFile.runWriteAction { | ||
val facade = JavaPsiFacade.getElementFactory(expressions.project) | ||
for (i in 0 until length) { | ||
val expression = expressions.expressions[startPosition + i] | ||
val node = expression.node | ||
val value = if (expression is PsiLiteralExpression) (components[i] / 255f).format() else "${components[i]} / 255f" | ||
val newExpression = facade.createExpressionFromText(value, null) | ||
|
||
node.psi.replace(newExpression) | ||
} | ||
} | ||
} | ||
|
||
object Deserializer : JsonDeserializer<FloatVectorParam> { | ||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): FloatVectorParam { | ||
val obj = json.asJsonObject | ||
return FloatVectorParam( | ||
obj["startPosition"]?.asInt ?: 0, | ||
obj["description"]?.asString ?: "Color", | ||
obj["hasAlpha"]?.asBoolean ?: true | ||
) | ||
} | ||
} | ||
} | ||
|
||
data class IntVectorParam(val startIndex: Int, override val description: String, override val hasAlpha: Boolean) : Param { | ||
val length = if (hasAlpha) 4 else 3 | ||
val endIndexExclusive = startIndex + length | ||
|
||
override fun extractColor(call: PsiCall): McpColorResult<Color>? { | ||
if (validateCall(call).isNotEmpty()) { | ||
return null | ||
} | ||
|
||
val args = call.argumentList ?: return null | ||
val colorArgs = args.expressions.toList().subList(startIndex, endIndexExclusive) | ||
val components = colorArgs.mapNotNull { evaluate(it) } | ||
if (components.size < length) { | ||
return null | ||
} | ||
val r = components[0] | ||
val g = components[1] | ||
val b = components[2] | ||
val a = components.getOrNull(3) ?: 255 | ||
|
||
return McpColorResult(call, this, Color(r, g, b, a), colorArgs[0].textRange.union(colorArgs[length - 1].textRange)) | ||
} | ||
|
||
private fun evaluate(element: PsiElement): Int? { | ||
val facade = JavaPsiFacade.getInstance(element.project) | ||
return facade.constantEvaluationHelper.computeConstantExpression(element) as? Int | ||
} | ||
|
||
override fun extractColor(result: McpColorResult<Any>): Color? { | ||
val call = result.expression as? PsiCall ?: return null | ||
return extractColor(call)?.arg | ||
} | ||
|
||
override fun validateCall(call: PsiCall): List<McpColorResult<McpColorWarning>> { | ||
val args = call.argumentList ?: return emptyList() | ||
val colorArgs = args.expressions.toList().subList(startIndex, endIndexExclusive) | ||
val components = colorArgs.mapNotNull(::evaluate) | ||
if (components.size < length) { | ||
return emptyList() | ||
} | ||
|
||
val outOfRange = components.withIndex() | ||
.filter { it.value !in 0..255 } | ||
.map { | ||
McpColorResult( | ||
colorArgs[it.index], | ||
this, | ||
McpColorWarning.ComponentOutOfRange("0", "255") { _ -> | ||
val literal = colorArgs[it.index] | ||
literal.containingFile.runWriteAction { | ||
val node = literal.node | ||
|
||
val literalExpression = JavaPsiFacade.getElementFactory(literal.project) | ||
.createExpressionFromText(it.value.coerceIn(0, 255).toString(), null) as PsiLiteralExpression | ||
|
||
node.psi.replace(literalExpression) | ||
} | ||
} | ||
) | ||
}.toList() | ||
|
||
return outOfRange | ||
} | ||
|
||
override fun setColor(context: McpColorResult<Color>) { | ||
val call = context.expression as? PsiCall ?: return | ||
val expressions = call.argumentList ?: return | ||
|
||
val color = context.arg | ||
val components = arrayOf(color.red, color.green, color.blue, color.alpha) | ||
|
||
expressions.containingFile.runWriteAction { | ||
val facade = JavaPsiFacade.getElementFactory(expressions.project) | ||
for (i in 0 until length) { | ||
val expression = expressions.expressions[startIndex + i] | ||
val node = expression.node | ||
val newExpression = facade.createExpressionFromText(components[i].toString(), null) | ||
|
||
node.psi.replace(newExpression) | ||
} | ||
} | ||
} | ||
|
||
object Deserializer : JsonDeserializer<IntVectorParam> { | ||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): IntVectorParam { | ||
val obj = json.asJsonObject | ||
return IntVectorParam( | ||
obj["startPosition"]?.asInt ?: 0, | ||
obj["description"]?.asString ?: "Color", | ||
obj["hasAlpha"]?.asBoolean ?: true | ||
) | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun Float.format(): String { | ||
val number = if (this == 0f || this == 1f) this.toInt().toString() else this.toString() | ||
return "${number}f" | ||
} |
117 changes: 117 additions & 0 deletions
117
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/McpColorMethods.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color | ||
|
||
import com.demonwav.mcdev.facet.MinecraftFacet | ||
import com.demonwav.mcdev.platform.mcp.McpModuleType | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod.FloatVectorParam | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod.IntVectorParam | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod.Param | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod.SingleIntParam | ||
import com.demonwav.mcdev.util.MemberReference | ||
import com.demonwav.mcdev.util.SemanticVersion | ||
import com.google.gson.GsonBuilder | ||
import com.google.gson.JsonDeserializationContext | ||
import com.google.gson.JsonDeserializer | ||
import com.google.gson.JsonElement | ||
import com.intellij.openapi.module.ModuleUtilCore | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.util.io.inputStream | ||
import java.io.InputStream | ||
import java.io.InputStreamReader | ||
import java.lang.reflect.Type | ||
import java.net.URI | ||
import java.nio.file.FileSystems | ||
import java.nio.file.Files | ||
import java.nio.file.Path | ||
import java.nio.file.Paths | ||
import kotlin.streams.toList | ||
|
||
object McpColorMethods { | ||
private val entries by lazy { | ||
val result = load() | ||
result.mapValues { ref -> | ||
result.entries.filter { it.key <= ref.key } | ||
.sortedBy { it.key } | ||
.map { it.value } | ||
.reduce { acc, cur -> | ||
acc.filter { a -> cur.none { b -> a.member == b.member } } + cur | ||
} | ||
} | ||
} | ||
|
||
operator fun get(elem: PsiElement): List<McpColorMethod> { | ||
val module = ModuleUtilCore.findModuleForPsiElement(elem) ?: return emptyList() | ||
val facet = MinecraftFacet.getInstance(module) ?: return emptyList() | ||
return facet.getModuleOfType(McpModuleType)?.colorMethods ?: emptyList() | ||
} | ||
|
||
operator fun get(mcVersion: String): List<McpColorMethod> { | ||
val semVer = SemanticVersion.parse(mcVersion) | ||
return entries.entries.findLast { it.key <= semVer }?.value ?: emptyList() | ||
} | ||
|
||
private fun load(): Map<SemanticVersion, List<McpColorMethod>> { | ||
val url = javaClass.getResource("/configs/mcp/colors") | ||
val files = url.toURI().listFiles() | ||
return files | ||
.filter { it.fileName.toString().endsWith(".json") } | ||
.associate { | ||
val version = SemanticVersion.parse(it.fileName.toString().substringBeforeLast('.')) | ||
version to load(it.inputStream()) | ||
} | ||
} | ||
|
||
private fun URI.listFiles(): List<Path> { | ||
val parts = this.toString().split("!", limit = 2) | ||
val path = when (parts.size) { | ||
1 -> Paths.get(this) | ||
else -> { | ||
val env = mutableMapOf<String, String>() | ||
FileSystems.newFileSystem(URI.create(parts[0]), env).getPath(parts[1]) | ||
} | ||
} | ||
return Files.list(path).toList() | ||
} | ||
|
||
private fun load(stream: InputStream): List<McpColorMethod> { | ||
val content = InputStreamReader(stream) | ||
val gson = GsonBuilder() | ||
.registerTypeAdapter(Param::class.java, McpMethodParamDeserializer) | ||
.registerTypeAdapter(MemberReference::class.java, MemberReferenceDeserializer) | ||
.create() | ||
return gson.fromJson(content, McpColorFile::class.java).entries | ||
} | ||
|
||
class McpColorFile(val entries: List<McpColorMethod>) | ||
|
||
object McpMethodParamDeserializer : JsonDeserializer<Param> { | ||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): Param { | ||
val obj = json.asJsonObject | ||
val discriminator = obj.get("type").asString | ||
return when (discriminator) { | ||
"intvec" -> IntVectorParam.Deserializer.deserialize(json, type, ctx) | ||
"floatvec" -> FloatVectorParam.Deserializer.deserialize(json, type, ctx) | ||
else -> SingleIntParam.Deserializer.deserialize(json, type, ctx) | ||
} | ||
} | ||
} | ||
|
||
object MemberReferenceDeserializer : JsonDeserializer<MemberReference> { | ||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): MemberReference { | ||
val ref = json.asString | ||
val className = ref.substringBefore('#') | ||
val methodName = ref.substring(className.length + 1, ref.indexOf("(")) | ||
val methodDesc = ref.substring(className.length + methodName.length + 1) | ||
return MemberReference(methodName, methodDesc, className) | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/McpColorResult.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color | ||
|
||
import com.intellij.openapi.util.TextRange | ||
import com.intellij.psi.PsiElement | ||
|
||
data class McpColorResult<out A>( | ||
val expression: PsiElement, | ||
val param: McpColorMethod.Param, | ||
val arg: A, | ||
val argRange: TextRange = expression.textRange | ||
) { | ||
fun <A> withArg(arg: A) = McpColorResult(expression, param, arg, argRange) | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/McpColorUtil.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color | ||
|
||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiMethodCallExpression | ||
import java.awt.Color | ||
|
||
fun PsiElement.findColors(): List<McpColorResult<Color>> { | ||
if (this !is PsiMethodCallExpression) { | ||
return emptyList() | ||
} | ||
|
||
val method = McpColorMethods[this].find { it.match(this) } ?: return emptyList() | ||
|
||
return method.extractColors(this) | ||
} |
24 changes: 24 additions & 0 deletions
24
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/McpColorWarning.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color | ||
|
||
sealed class McpColorWarning { | ||
object NoHex : McpColorWarning() | ||
|
||
data class MissingComponents(val components: List<String>) : McpColorWarning() | ||
|
||
object MissingAlpha : McpColorWarning() | ||
|
||
object SuperfluousAlpha : McpColorWarning() | ||
|
||
data class ComponentOutOfRange(val min: String, val max: String, val clamp: (McpColorResult<Any>) -> Unit) : McpColorWarning() | ||
} | ||
|
67 changes: 67 additions & 0 deletions
67
...n/com/demonwav/mcdev/platform/mcp/color/inspections/ColorComponentOutOfRangeInspection.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color.inspections | ||
|
||
import com.demonwav.mcdev.facet.MinecraftFacet | ||
import com.demonwav.mcdev.platform.mcp.McpModuleType | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethods | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorResult | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorWarning | ||
import com.demonwav.mcdev.platform.mcp.color.findColors | ||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.module.ModuleUtilCore | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.PsiCallExpression | ||
import com.siyeh.ig.BaseInspection | ||
import com.siyeh.ig.BaseInspectionVisitor | ||
import com.siyeh.ig.InspectionGadgetsFix | ||
import org.jetbrains.annotations.Nls | ||
|
||
class ColorComponentOutOfRangeInspection : BaseInspection() { | ||
@Nls | ||
override fun getDisplayName(): String { | ||
return "MCP Color component out of range" | ||
} | ||
|
||
override fun buildErrorString(vararg infos: Any): String { | ||
return "Color component is out of [${infos[1]},${infos[2]}] range, this can lead to unexpected behavior." | ||
} | ||
|
||
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? { | ||
val result = infos[0] as? McpColorResult<McpColorWarning> ?: return null | ||
val clamp = infos[3] as? (McpColorResult<Any>) -> Unit ?: return null | ||
return object : InspectionGadgetsFix() { | ||
override fun doFix(project: Project, descriptor: ProblemDescriptor) { | ||
clamp(result) | ||
} | ||
|
||
@Nls | ||
override fun getName() = "Clamp value to range" | ||
|
||
@Nls | ||
override fun getFamilyName() = "MCP Colors" | ||
} | ||
} | ||
|
||
override fun buildVisitor(): BaseInspectionVisitor { | ||
return object : BaseInspectionVisitor() { | ||
override fun visitCallExpression(call: PsiCallExpression) { | ||
val results = McpColorMethods[call].flatMap { it.validateCall(call) } | ||
for (result in results) { | ||
if (result.arg is McpColorWarning.ComponentOutOfRange) { | ||
registerError(result.expression, result, result.arg.min, result.arg.max, result.arg.clamp) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
...n/kotlin/com/demonwav/mcdev/platform/mcp/color/inspections/ColorMissingAlphaInspection.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color.inspections | ||
|
||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethods | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorResult | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorWarning | ||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.PsiCallExpression | ||
import com.siyeh.ig.BaseInspection | ||
import com.siyeh.ig.BaseInspectionVisitor | ||
import com.siyeh.ig.InspectionGadgetsFix | ||
import org.jetbrains.annotations.Nls | ||
import java.awt.Color | ||
|
||
class ColorMissingAlphaInspection : BaseInspection() { | ||
@Nls | ||
override fun getDisplayName(): String { | ||
return "MCP Color missing alpha component" | ||
} | ||
|
||
override fun buildErrorString(vararg infos: Any): String { | ||
return "This method expects its color argument to have an alpha component. " + | ||
"Without an explicit alpha value, the color will be considered fully transparent." | ||
} | ||
|
||
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? { | ||
val result = infos[0] as? McpColorResult<McpColorWarning> ?: return null | ||
return object : InspectionGadgetsFix() { | ||
override fun doFix(project: Project, descriptor: ProblemDescriptor) { | ||
val color = result.param.extractColor(result) ?: return | ||
result.param.setColor(result.withArg(Color(0xFF000000.toInt() or color.rgb, true))) | ||
} | ||
|
||
@Nls | ||
override fun getName() = "Add fully opaque alpha component" | ||
|
||
@Nls | ||
override fun getFamilyName() = "MCP Colors" | ||
} | ||
} | ||
|
||
override fun buildVisitor(): BaseInspectionVisitor { | ||
return object : BaseInspectionVisitor() { | ||
override fun visitCallExpression(call: PsiCallExpression) { | ||
val results = McpColorMethods[call].flatMap { it.validateCall(call) } | ||
for (result in results) { | ||
if (result.arg == McpColorWarning.MissingAlpha) { | ||
registerError(result.expression, result) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
...tlin/com/demonwav/mcdev/platform/mcp/color/inspections/ColorSuperfluousAlphaInspection.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color.inspections | ||
|
||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethods | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorResult | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorWarning | ||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.PsiCallExpression | ||
import com.siyeh.ig.BaseInspection | ||
import com.siyeh.ig.BaseInspectionVisitor | ||
import com.siyeh.ig.InspectionGadgetsFix | ||
import org.jetbrains.annotations.Nls | ||
import java.awt.Color | ||
|
||
class ColorSuperfluousAlphaInspection : BaseInspection() { | ||
@Nls | ||
override fun getDisplayName(): String { | ||
return "MCP Color superfluous alpha component" | ||
} | ||
|
||
override fun buildErrorString(vararg infos: Any): String { | ||
return "This method does not expect an alpha component" | ||
} | ||
|
||
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? { | ||
val result = infos[0] as? McpColorResult<McpColorWarning> ?: return null | ||
return object : InspectionGadgetsFix() { | ||
override fun doFix(project: Project, descriptor: ProblemDescriptor) { | ||
val color = result.param.extractColor(result) ?: return | ||
result.param.setColor(result.withArg(Color(0xFFFFFF and color.rgb, false))) | ||
} | ||
|
||
@Nls | ||
override fun getName() = "Remove alpha component" | ||
|
||
@Nls | ||
override fun getFamilyName() = "MCP Colors" | ||
} | ||
} | ||
|
||
override fun buildVisitor(): BaseInspectionVisitor { | ||
return object : BaseInspectionVisitor() { | ||
override fun visitCallExpression(call: PsiCallExpression) { | ||
val results = McpColorMethods[call].flatMap { it.validateCall(call) } | ||
for (result in results) { | ||
if (result.arg == McpColorWarning.SuperfluousAlpha) { | ||
registerError(result.expression, result) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
...tlin/com/demonwav/mcdev/platform/mcp/color/inspections/MissingColorComponentInspection.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color.inspections | ||
|
||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethods | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorResult | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorWarning | ||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.PsiCallExpression | ||
import com.siyeh.ig.BaseInspection | ||
import com.siyeh.ig.BaseInspectionVisitor | ||
import com.siyeh.ig.InspectionGadgetsFix | ||
import org.jetbrains.annotations.Nls | ||
import java.awt.Color | ||
|
||
class MissingColorComponentInspection : BaseInspection() { | ||
@Nls | ||
override fun getDisplayName(): String { | ||
return "MCP Color missing one or more component" | ||
} | ||
|
||
override fun buildErrorString(vararg infos: Any): String { | ||
return "Color missing ${(infos[1] as List<String>).joinToString(" and ")} component (implied as zero)" | ||
} | ||
|
||
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? { | ||
val result = infos[0] as? McpColorResult<McpColorWarning> ?: return null | ||
return object : InspectionGadgetsFix() { | ||
override fun doFix(project: Project, descriptor: ProblemDescriptor) { | ||
val color = result.param.extractColor(result) ?: return | ||
val newColor = if (!result.param.hasAlpha) 0xFFFFFF and color.rgb else color.rgb | ||
result.param.setColor(result.withArg(Color(newColor, result.param.hasAlpha))) | ||
} | ||
|
||
@Nls | ||
override fun getName() = "Pad color with zero components" | ||
|
||
@Nls | ||
override fun getFamilyName() = "MCP Colors" | ||
} | ||
} | ||
|
||
override fun buildVisitor(): BaseInspectionVisitor { | ||
return object : BaseInspectionVisitor() { | ||
override fun visitCallExpression(call: PsiCallExpression) { | ||
val results = McpColorMethods[call].flatMap { it.validateCall(call) } | ||
for (result in results) { | ||
if (result.arg is McpColorWarning.MissingComponents) { | ||
registerError(result.expression, result, result.arg.components) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
src/main/kotlin/com/demonwav/mcdev/platform/mcp/color/inspections/NonHexColorInspection.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Minecraft Dev for IntelliJ | ||
* | ||
* https://minecraftdev.org | ||
* | ||
* Copyright (c) 2018 minecraft-dev | ||
* | ||
* MIT License | ||
*/ | ||
|
||
package com.demonwav.mcdev.platform.mcp.color.inspections | ||
|
||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethod | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorMethods | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorResult | ||
import com.demonwav.mcdev.platform.mcp.color.McpColorWarning | ||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.PsiCallExpression | ||
import com.siyeh.ig.BaseInspection | ||
import com.siyeh.ig.BaseInspectionVisitor | ||
import com.siyeh.ig.InspectionGadgetsFix | ||
import org.jetbrains.annotations.Nls | ||
import java.awt.Color | ||
|
||
class NonHexColorInspection : BaseInspection() { | ||
@Nls | ||
override fun getDisplayName(): String { | ||
return "MCP Color using non-hex literal" | ||
} | ||
|
||
override fun buildErrorString(vararg infos: Any): String { | ||
return "Color arguments should use hex literal for easily identifying color components." | ||
} | ||
|
||
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? { | ||
val result = infos[0] as? McpColorResult<McpColorWarning> ?: return null | ||
return object : InspectionGadgetsFix() { | ||
override fun doFix(project: Project, descriptor: ProblemDescriptor) { | ||
val color = result.param.extractColor(result) ?: return | ||
val newColor = if (!result.param.hasAlpha) 0xFFFFFF and color.rgb else color.rgb | ||
result.param.setColor(result.withArg(Color(newColor, result.param.hasAlpha))) | ||
} | ||
|
||
@Nls | ||
override fun getName() = "Convert to hex literal" | ||
|
||
@Nls | ||
override fun getFamilyName() = "MCP Colors" | ||
} | ||
} | ||
|
||
override fun buildVisitor(): BaseInspectionVisitor { | ||
return object : BaseInspectionVisitor() { | ||
override fun visitCallExpression(call: PsiCallExpression) { | ||
val results = McpColorMethods[call].flatMap { it.validateCall(call) } | ||
for (result in results) { | ||
if (result.arg == McpColorWarning.NoHex) { | ||
registerError(result.expression, result) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
{ | ||
"entries": [ | ||
{ | ||
"__comment": "drawRect", | ||
"member": "net.minecraft.client.gui.Gui#func_73734_a(IIIII)V", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "int", | ||
"description": "Rectangle Color", | ||
"position": 4, | ||
"hasAlpha": true | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "drawHorizontalLine", | ||
"member": "net.minecraft.client.gui.Gui#func_73730_a(IIII)V", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "int", | ||
"description": "Line Color", | ||
"position": 3, | ||
"hasAlpha": true | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "drawVerticalLine", | ||
"member": "net.minecraft.client.gui.Gui#func_73728_b(IIII)V", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "int", | ||
"description": "Line Color", | ||
"position": 3, | ||
"hasAlpha": true | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "drawGradientRect", | ||
"member": "net.minecraft.client.gui.Gui#func_73733_a(IIIIII)V", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "int", | ||
"description": "Start Color", | ||
"position": 4, | ||
"hasAlpha": true | ||
}, | ||
{ | ||
"type": "int", | ||
"description": "End Color", | ||
"position": 5, | ||
"hasAlpha": true | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "clearColor", | ||
"member": "net.minecraft.client.renderer.GlStateManager#func_179082_a(FFFF)V", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "floatvec", | ||
"description": "Clear Color", | ||
"startPosition": 0, | ||
"hasAlpha": true | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "color4f", | ||
"member": "net.minecraft.client.renderer.GlStateManager#func_179131_c(FFFF)V", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "floatvec", | ||
"description": "Color Multiplier", | ||
"startPosition": 0, | ||
"hasAlpha": true | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "color3f", | ||
"member": "net.minecraft.client.renderer.GlStateManager#func_179124_c(FFF)V", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "floatvec", | ||
"description": "Color Multiplier", | ||
"startPosition": 0, | ||
"hasAlpha": false | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "color4f", | ||
"member": "net.minecraft.client.renderer.BufferBuilder#func_181666_a(FFFF)Lnet/minecraft/client/renderer/BufferBuilder;", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "floatvec", | ||
"description": "Color Multiplier", | ||
"startPosition": 0, | ||
"hasAlpha": true | ||
} | ||
] | ||
}, | ||
{ | ||
"__comment": "color4i", | ||
"member": "net.minecraft.client.renderer.BufferBuilder#func_181669_b(IIII)Lnet/minecraft/client/renderer/BufferBuilder;", | ||
"srgName": true, | ||
"params": [ | ||
{ | ||
"type": "intvec", | ||
"description": "Color Multiplier", | ||
"startPosition": 0, | ||
"hasAlpha": true | ||
} | ||
] | ||
} | ||
] | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid introducing new inspections built on
BaseInspection
? In my opinion that class is pretty much obsolete and most things can be implemented with one of IntelliJ's base classes (here:AbstractBaseJavaLocalInspectionTool
) in a nicer way.