From af9222c8fd25f7304b537b3148159133ed790d19 Mon Sep 17 00:00:00 2001 From: RedNesto Date: Wed, 4 Nov 2020 21:43:59 +0100 Subject: [PATCH 1/5] Port Color & Listeners support to UAST --- src/main/kotlin/insight/ColorAnnotator.kt | 4 +- .../kotlin/insight/ColorLineMarkerProvider.kt | 52 +++-- src/main/kotlin/insight/ColorUtil.kt | 217 ++++++++---------- src/main/kotlin/insight/InsightUtil.kt | 50 ++-- .../kotlin/insight/ListenerEventAnnotator.kt | 58 ++--- .../insight/ListenerLineMarkerProvider.kt | 20 +- .../color/AdventureColorLineMarkerProvider.kt | 3 +- .../adventure/color/AdventureColorUtil.kt | 7 +- .../color/SpongeColorLineMarkerProvider.kt | 3 +- .../platform/sponge/color/SpongeColorUtil.kt | 7 +- src/main/resources/META-INF/plugin.xml | 6 +- 11 files changed, 214 insertions(+), 213 deletions(-) diff --git a/src/main/kotlin/insight/ColorAnnotator.kt b/src/main/kotlin/insight/ColorAnnotator.kt index 4fd8d358b..e9e915d1f 100644 --- a/src/main/kotlin/insight/ColorAnnotator.kt +++ b/src/main/kotlin/insight/ColorAnnotator.kt @@ -18,6 +18,8 @@ import com.intellij.openapi.editor.markup.TextAttributes import com.intellij.psi.PsiElement import java.awt.Color import java.awt.Font +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType class ColorAnnotator : Annotator { @@ -26,7 +28,7 @@ class ColorAnnotator : Annotator { return } - val color = element.findColor { _, chosenEntry -> chosenEntry.value } ?: return + val color = element.toUElementOfType()?.findColor { _, chosenEntry -> chosenEntry.value } ?: return setColorAnnotator(color, element, holder) } diff --git a/src/main/kotlin/insight/ColorLineMarkerProvider.kt b/src/main/kotlin/insight/ColorLineMarkerProvider.kt index 382acba79..d5c323d9a 100644 --- a/src/main/kotlin/insight/ColorLineMarkerProvider.kt +++ b/src/main/kotlin/insight/ColorLineMarkerProvider.kt @@ -16,13 +16,11 @@ 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.codeInsight.hint.HintManager import com.intellij.icons.AllIcons import com.intellij.openapi.editor.markup.GutterIconRenderer +import com.intellij.psi.JVMElementFactories import com.intellij.psi.PsiElement -import com.intellij.psi.PsiExpressionList -import com.intellij.psi.PsiLiteralExpression -import com.intellij.psi.PsiNewExpression -import com.intellij.psi.impl.source.tree.JavaElementType import com.intellij.psi.util.PsiEditorUtil import com.intellij.ui.ColorChooser import com.intellij.util.FunctionUtil @@ -30,6 +28,11 @@ import com.intellij.util.ui.ColorIcon import com.intellij.util.ui.ColorsIcon import java.awt.Color import javax.swing.Icon +import org.jetbrains.uast.UCallExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.ULiteralExpression +import org.jetbrains.uast.toUElementOfType class ColorLineMarkerProvider : LineMarkerProvider { @@ -38,7 +41,8 @@ class ColorLineMarkerProvider : LineMarkerProvider { return null } - val info = element.findColor { map, chosen -> ColorInfo(element, chosen.value, map, chosen.key) } + val identifier = element.toUElementOfType() ?: return null + val info = identifier.findColor { map, chosen -> ColorInfo(element, chosen.value, map, chosen.key, identifier) } if (info != null) { NavigateAction.setNavigateAction(info, "Change Color", null) } @@ -49,7 +53,13 @@ class ColorLineMarkerProvider : LineMarkerProvider { open class ColorInfo : MergeableLineMarkerInfo { protected val color: Color - constructor(element: PsiElement, color: Color, map: Map, colorName: String) : super( + constructor( + element: PsiElement, + color: Color, + map: Map, + colorName: String, + workElement: UElement + ) : super( element, element.textRange, ColorIcon(12, color), @@ -63,8 +73,8 @@ class ColorLineMarkerProvider : LineMarkerProvider { val picker = ColorPicker(map, editor.component) val newColor = picker.showDialog() - if (newColor != null) { - element.setColor(newColor) + if (newColor != null && map[newColor] != color) { + workElement.setColor(newColor) } }, GutterIconRenderer.Alignment.RIGHT, @@ -103,7 +113,7 @@ class ColorLineMarkerProvider : LineMarkerProvider { class CommonColorInfo( element: PsiElement, color: Color, - workElement: PsiElement + workElement: UElement ) : ColorLineMarkerProvider.ColorInfo( element, color, @@ -113,18 +123,20 @@ class ColorLineMarkerProvider : LineMarkerProvider { } val editor = PsiEditorUtil.findEditor(element) ?: return@handler + if (JVMElementFactories.getFactory(element.language, element.project) == null) { + // The setColor methods used here require a JVMElementFactory. Unfortunately the Kotlin plugin does not + // implement it yet. It is better to not display the color chooser at all than deceiving users after + // after they chose a color + HintManager.getInstance() + .showErrorHint(editor, "Can't change colors in " + element.language.displayName) + return@handler + } val c = ColorChooser.chooseColor(editor.component, "Choose Color", color, false) - if (c != null) { - when (workElement) { - is PsiLiteralExpression -> workElement.setColor(c.rgb and 0xFFFFFF) - is PsiExpressionList -> workElement.setColor(c.red, c.green, c.blue) - is PsiNewExpression -> { - val list = workElement.getNode().findChildByType(JavaElementType.EXPRESSION_LIST) - as PsiExpressionList? - list?.setColor(c.red, c.green, c.blue) - } - } + ?: return@handler + when (workElement) { + is ULiteralExpression -> workElement.setColor(c.rgb and 0xFFFFFF) + is UCallExpression -> workElement.setColor(c.red, c.green, c.blue) } } ) @@ -139,6 +151,6 @@ class ColorLineMarkerProvider : LineMarkerProvider { return info } - abstract fun findColor(element: PsiElement): Pair? + abstract fun findColor(element: PsiElement): Pair? } } diff --git a/src/main/kotlin/insight/ColorUtil.kt b/src/main/kotlin/insight/ColorUtil.kt index 860ec6a42..5b33cc173 100644 --- a/src/main/kotlin/insight/ColorUtil.kt +++ b/src/main/kotlin/insight/ColorUtil.kt @@ -13,30 +13,30 @@ package com.demonwav.mcdev.insight import com.demonwav.mcdev.facet.MinecraftFacet import com.demonwav.mcdev.platform.AbstractModule import com.demonwav.mcdev.platform.AbstractModuleType +import com.demonwav.mcdev.util.findModule import com.demonwav.mcdev.util.runWriteAction import com.intellij.openapi.module.ModuleUtilCore -import com.intellij.psi.JavaPsiFacade -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiExpressionList -import com.intellij.psi.PsiIdentifier -import com.intellij.psi.PsiLiteralExpression -import com.intellij.psi.PsiMethodCallExpression -import com.intellij.psi.PsiNewExpression -import com.intellij.psi.PsiReferenceExpression +import com.intellij.psi.JVMElementFactories import com.intellij.psi.PsiType -import com.intellij.psi.impl.source.tree.JavaElementType import com.intellij.psi.search.GlobalSearchScope import java.awt.Color - -fun PsiElement.findColor(function: (Map, Map.Entry) -> T): T? { - if (this !is PsiIdentifier) { - return null - } - - val expression = this.parent as? PsiReferenceExpression ?: return null - val type = expression.type ?: return null - - val module = ModuleUtilCore.findModuleForPsiElement(this) ?: return null +import kotlin.math.round +import org.jetbrains.uast.UCallExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.ULiteralExpression +import org.jetbrains.uast.UQualifiedReferenceExpression +import org.jetbrains.uast.UReferenceExpression +import org.jetbrains.uast.generate.generationPlugin +import org.jetbrains.uast.generate.replace + +fun UIdentifier.findColor(function: (Map, Map.Entry) -> T): T? { + val parent = this.uastParent + val expression = parent as? UReferenceExpression ?: return null + val type = expression.getExpressionType() ?: return null + + val module = this.sourcePsi?.findModule() ?: return null val facet = MinecraftFacet.getInstance(module) ?: return null for (abstractModuleType in facet.types) { val map = abstractModuleType.classToColorMappings @@ -45,7 +45,9 @@ fun PsiElement.findColor(function: (Map, Map.Entry PsiElement.findColor(function: (Map, Map.Entry, className: String, vectorClasses: Array? -): Pair? { - if (this !is PsiIdentifier) { - return null - } - - val project = this.getProject() +): Pair? { + val sourcePsi = this.sourcePsi ?: return null + val project = sourcePsi.project - val module = ModuleUtilCore.findModuleForPsiElement(this) ?: return null + val module = ModuleUtilCore.findModuleForPsiElement(sourcePsi) ?: return null val facet = MinecraftFacet.getInstance(module) ?: return null @@ -72,118 +71,106 @@ fun PsiElement.findColor( return null } - val methodExpression = this.parent as? PsiReferenceExpression ?: return null - val qualifier = methodExpression.qualifier as? PsiReferenceExpression ?: return null - if (qualifier.qualifiedName != className) { + val methodExpression = uastParent as? UCallExpression ?: return null + if (methodExpression.resolve()?.containingClass?.qualifiedName != className) { return null } - val methodCallExpression = methodExpression.parent as? PsiMethodCallExpression ?: return null - val expressionList = methodCallExpression.argumentList - val types = expressionList.expressionTypes + val arguments = methodExpression.valueArguments + val types = arguments.map(UExpression::getExpressionType) - when { + return when { // Single Integer Argument - types.size == 1 && types[0] == PsiType.INT && expressionList.expressions[0] is PsiLiteralExpression -> { - try { - val expr = expressionList.expressions[0] as PsiLiteralExpression - return colorFromSingleArgument(expr) to expressionList.expressions[0] - } catch (ignored: Exception) { } - } + types.size == 1 && types[0] == PsiType.INT -> + colorFromSingleArgument(arguments[0])?.let { it to arguments[0] } // Triple Integer Argument - types.size == 3 && types[0] == PsiType.INT && types[1] == PsiType.INT && types[2] == PsiType.INT -> { - try { - return colorFromThreeArguments(expressionList) to expressionList - } catch (ignored: Exception) { } - } + types.size == 3 && types.all { it == PsiType.INT } -> + colorFromThreeArguments(arguments)?.let { it to methodExpression } vectorClasses != null && types.size == 1 -> { val scope = GlobalSearchScope.allScope(project) - for (vectorClass in vectorClasses) { - if (types[0] == PsiType.getTypeByName(vectorClass, project, scope)) { - try { - val color = colorFromVectorArgument(expressionList.expressions[0] as PsiNewExpression) - return color to expressionList.expressions[0] - } catch (ignored: Exception) {} - } + if (vectorClasses.any { types[0] == PsiType.getTypeByName(it, project, scope) }) { + (arguments[0] as? UCallExpression)?.takeIf { it.valueArgumentCount == 3 } + ?.let(::colorFromVectorArgument) + ?.let { it to arguments[0] } + } else { + null } } + else -> null } - - return null } -fun PsiElement.setColor(color: String) { - this.containingFile.runWriteAction { - val split = color.split(".").dropLastWhile(String::isEmpty).toTypedArray() - val newColorBase = split.last() - - val identifier = JavaPsiFacade.getElementFactory(this.project).createIdentifier(newColorBase) - - this.replace(identifier) - } +private fun colorFromSingleArgument(expression: UExpression): Color? { + return Color(expression.evaluate() as? Int ?: return null) } -fun PsiLiteralExpression.setColor(value: Int) { - this.containingFile.runWriteAction { - val node = this.node - - val literalExpression = JavaPsiFacade.getElementFactory(this.project) - .createExpressionFromText("0x" + Integer.toHexString(value).toUpperCase(), null) as PsiLiteralExpression - - node.psi.replace(literalExpression) +private fun colorFromThreeArguments(expressions: List): Color? { + fun normalize(value: Any?): Int? = when (value) { + is Int -> value + is Float -> round(value).toInt() + is Double -> round(value).toInt() + else -> null } -} - -fun PsiExpressionList.setColor(red: Int, green: Int, blue: Int) { - this.containingFile.runWriteAction { - val expressionOne = this.expressions[0] - val expressionTwo = this.expressions[1] - val expressionThree = this.expressions[2] - - val nodeOne = expressionOne.node - val nodeTwo = expressionTwo.node - val nodeThree = expressionThree.node - val facade = JavaPsiFacade.getElementFactory(this.project) - - val literalExpressionOne = facade.createExpressionFromText(red.toString(), null) - val literalExpressionTwo = facade.createExpressionFromText(green.toString(), null) - val literalExpressionThree = facade.createExpressionFromText(blue.toString(), null) - - nodeOne.psi.replace(literalExpressionOne) - nodeTwo.psi.replace(literalExpressionTwo) - nodeThree.psi.replace(literalExpressionThree) - } + val r = normalize(expressions[0].evaluate()) ?: return null + val g = normalize(expressions[1].evaluate()) ?: return null + val b = normalize(expressions[2].evaluate()) ?: return null + return Color(r, g, b) } -private fun colorFromSingleArgument(expression: PsiLiteralExpression): Color { - val value = Integer.decode(expression.text)!! - - return Color(value) +private fun colorFromVectorArgument(newExpression: UCallExpression): Color? { + return colorFromThreeArguments(newExpression.valueArguments) } -private fun colorFromThreeArguments(expressionList: PsiExpressionList): Color { - if (expressionList.expressions[0] !is PsiLiteralExpression || - expressionList.expressions[1] !is PsiLiteralExpression || - expressionList.expressions[2] !is PsiLiteralExpression - ) { - throw Exception() +fun UElement.setColor(color: String) { + val sourcePsi = this.sourcePsi ?: return + sourcePsi.containingFile.runWriteAction { + val project = sourcePsi.project + val parent = this.uastParent + val newColorRef = generationPlugin?.getElementFactory(project)?.createQualifiedReference(color, this) + ?: return@runWriteAction + if (this.lang.id == "kotlin") { + // Kotlin UAST is a bit different, annoying but I couldn't find a better way + val grandparent = parent?.uastParent + if (grandparent is UQualifiedReferenceExpression) { + grandparent.replace(newColorRef) + } else { + this.replace(newColorRef) + } + } else { + if (parent is UQualifiedReferenceExpression) { + parent.replace(newColorRef) + } else { + this.replace(newColorRef) + } + } } +} - val expressionOne = expressionList.expressions[0] as PsiLiteralExpression - val expressionTwo = expressionList.expressions[1] as PsiLiteralExpression - val expressionThree = expressionList.expressions[2] as PsiLiteralExpression +fun ULiteralExpression.setColor(value: Int) { + val sourcePsi = this.sourcePsi ?: return + sourcePsi.containingFile.runWriteAction { + JVMElementFactories.requireFactory(sourcePsi.language, sourcePsi.project) + .createExpressionFromText("0x" + Integer.toHexString(value).toUpperCase(), sourcePsi) + .let(sourcePsi::replace) + } +} - val one = Math.round(expressionOne.text.toDouble()).toInt() - val two = Math.round(expressionTwo.text.toDouble()).toInt() - val three = Math.round(expressionThree.text.toDouble()).toInt() +fun UCallExpression.setColor(red: Int, green: Int, blue: Int) { + val sourcePsi = this.sourcePsi ?: return + sourcePsi.containingFile.runWriteAction { + val r = this.valueArguments[0] + val g = this.valueArguments[1] + val b = this.valueArguments[2] - return Color(one, two, three) -} + val factory = JVMElementFactories.requireFactory(sourcePsi.language, sourcePsi.project) -private fun colorFromVectorArgument(newExpression: PsiNewExpression): Color { - val expressionList = - newExpression.node.findChildByType(JavaElementType.EXPRESSION_LIST) as PsiExpressionList? ?: throw Exception() + val literalExpressionOne = factory.createExpressionFromText(red.toString(), null) + val literalExpressionTwo = factory.createExpressionFromText(green.toString(), null) + val literalExpressionThree = factory.createExpressionFromText(blue.toString(), null) - return colorFromThreeArguments(expressionList) + r.sourcePsi?.replace(literalExpressionOne) + g.sourcePsi?.replace(literalExpressionTwo) + b.sourcePsi?.replace(literalExpressionThree) + } } diff --git a/src/main/kotlin/insight/InsightUtil.kt b/src/main/kotlin/insight/InsightUtil.kt index f5b8fe1da..adf0c7663 100644 --- a/src/main/kotlin/insight/InsightUtil.kt +++ b/src/main/kotlin/insight/InsightUtil.kt @@ -12,36 +12,30 @@ package com.demonwav.mcdev.insight import com.demonwav.mcdev.facet.MinecraftFacet import com.intellij.openapi.module.ModuleUtilCore -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier -import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiClassType import com.intellij.psi.PsiModifier -import com.intellij.psi.PsiParameter -import com.intellij.psi.impl.source.PsiClassReferenceType +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UMethod +import org.jetbrains.uast.UParameter +import org.jetbrains.uast.toUElementOfType -val PsiElement.eventListener: Pair? +val UElement.uastEventListener: Pair? get() { - // Since we want to line up with the method declaration, not the annotation - // declaration, we need to target identifiers, not just PsiMethods. - if (!(this is PsiIdentifier && this.getParent() is PsiMethod)) { - return null - } // The PsiIdentifier is going to be a method of course! - val method = this.getParent() as PsiMethod - if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + val method = this.uastParent as? UMethod ?: return null + if (method.javaPsi.hasModifierProperty(PsiModifier.ABSTRACT)) { // I don't think any implementation allows for abstract method listeners. return null } - val modifierList = method.modifierList - val module = ModuleUtilCore.findModuleForPsiElement(this) ?: return null + val module = ModuleUtilCore.findModuleForPsiElement(this.sourcePsi ?: return null) ?: return null val instance = MinecraftFacet.getInstance(module) ?: return null // Since each platform has their own valid listener annotations, // some platforms may have multiple allowed annotations for various cases val listenerAnnotations = instance.types.flatMap { it.listenerAnnotations } var contains = false for (listenerAnnotation in listenerAnnotations) { - if (modifierList.findAnnotation(listenerAnnotation) != null) { + if (method.findAnnotation(listenerAnnotation) != null) { contains = true break } @@ -49,29 +43,25 @@ val PsiElement.eventListener: Pair? if (!contains) { return null } - val (_, resolve) = method.eventParameterPair ?: return null + val (_, resolve) = method.uastEventParameterPair ?: return null - if (!instance.isStaticListenerSupported(method) && method.hasModifierProperty(PsiModifier.STATIC)) { + if (!instance.isStaticListenerSupported(method.javaPsi) && method.isStatic) { return null } return resolve to method } -val PsiMethod.eventParameterPair: Pair? +val UMethod.uastEventParameterPair: Pair? get() { - val parameters = this.parameterList.parameters - if (parameters.isEmpty()) { - return null - } - val psiParameter = parameters[0] // Listeners must have at least a single parameter - ?: return null + val firstParameter = this.uastParameters.firstOrNull() + ?: return null // Listeners must have at least a single parameter // Get the type of the parameter so we can start resolving it - val psiEventElement = psiParameter.typeElement ?: return null - val type = psiEventElement.type as? PsiClassReferenceType ?: return null + @Suppress("UElementAsPsi") // UVariable overrides getType so it should be fine to use on UElements... + val type = firstParameter.type as? PsiClassType ?: return null // Validate that it is a class reference type // And again, make sure that we can at least resolve the type, otherwise it's not a valid // class reference. - val resolve = type.resolve() ?: return null - return psiParameter to resolve + val resolve = type.resolve()?.toUElementOfType() ?: return null + return firstParameter to resolve } diff --git a/src/main/kotlin/insight/ListenerEventAnnotator.kt b/src/main/kotlin/insight/ListenerEventAnnotator.kt index 965b64094..3019de70e 100644 --- a/src/main/kotlin/insight/ListenerEventAnnotator.kt +++ b/src/main/kotlin/insight/ListenerEventAnnotator.kt @@ -17,12 +17,18 @@ import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.openapi.module.ModuleUtilCore import com.intellij.psi.PsiClass +import com.intellij.psi.PsiClassType import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod import com.intellij.psi.PsiModifier -import com.intellij.psi.PsiParameter -import com.intellij.psi.impl.source.PsiClassReferenceType +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UMethod +import org.jetbrains.uast.UParameter +import org.jetbrains.uast.UTypeReferenceExpression +import org.jetbrains.uast.getParentOfType +import org.jetbrains.uast.getUastParentOfType +import org.jetbrains.uast.toUElement +import org.jetbrains.uast.toUElementOfType class ListenerEventAnnotator : Annotator { @@ -32,18 +38,19 @@ class ListenerEventAnnotator : Annotator { } // Since we want to line up with the method declaration, not the annotation - // declaration, we need to target identifiers, not just PsiMethods. - val method = when (element) { - is PsiIdentifier -> element.parent as? PsiMethod ?: return - is PsiParameter -> element.parent.parent as? PsiMethod ?: return - else -> return + // declaration, we need to target identifiers, not the whole method. + if (element.toUElementOfType() == null) { + return } - if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + val method: UMethod = element.toUElement()?.uastParent as? UMethod + ?: element.getUastParentOfType() + ?.getParentOfType()?.uastParent as? UMethod // Be sure to be on the type of a parameter + ?: return + if (method.javaPsi.hasModifierProperty(PsiModifier.ABSTRACT)) { // I don't think any implementation allows for abstract return } - val modifierList = method.modifierList val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return val instance = MinecraftFacet.getInstance(module) ?: return // Since each platform has their own valid listener annotations, @@ -53,7 +60,7 @@ class ListenerEventAnnotator : Annotator { for (moduleType in moduleTypes) { val listenerAnnotations = moduleType.listenerAnnotations for (listenerAnnotation in listenerAnnotations) { - if (modifierList.findAnnotation(listenerAnnotation) != null) { + if (method.findAnnotation(listenerAnnotation) != null) { contains = true break } @@ -63,35 +70,28 @@ class ListenerEventAnnotator : Annotator { return } - val parameters = method.parameterList.parameters - if (parameters.isEmpty()) { - return - } - val eventParameter = parameters[0] // Listeners must have at least a single parameter + val eventParameter = method.uastParameters.firstOrNull() // Listeners must have at least one parameter ?: return - // Get the type of the parameter so we can start resolving it - val psiEventElement = eventParameter.typeElement ?: return - val type = psiEventElement.type as? PsiClassReferenceType ?: return - // Validate that it is a class reference type + // Validate that this is a class reference type // And again, make sure that we can at least resolve the type, otherwise it's not a valid // class reference. - val eventClass = type.resolve() ?: return - - if (instance.isEventClassValid(eventClass, method)) { + val eventClass = (eventParameter.typeReference?.type as? PsiClassType)?.resolve() ?: return + if (instance.isEventClassValid(eventClass, method.javaPsi)) { return } - if (!instance.isStaticListenerSupported(method) && method.hasModifierProperty(PsiModifier.STATIC)) { - if (method.nameIdentifier != null) { + if (!instance.isStaticListenerSupported(method.javaPsi) && method.isStatic) { + method.javaPsi.nameIdentifier?.let { holder.newAnnotation(HighlightSeverity.ERROR, "Event listener method must not be static") - .range(method.nameIdentifier!!) + .range(it) .create() } } - if (element == eventParameter && !isSuperEventListenerAllowed(eventClass, method, instance)) { - // Only annotate the first parameter - val errorMessage = instance.writeErrorMessageForEvent(eventClass, method) + if (element.getUastParentOfType()?.sourcePsi == eventParameter.sourcePsi && + !isSuperEventListenerAllowed(eventClass, method.javaPsi, instance) + ) { + val errorMessage = instance.writeErrorMessageForEvent(eventClass, method.javaPsi) if (errorMessage == null) { holder.newSilentAnnotation(HighlightSeverity.ERROR).create() } else { diff --git a/src/main/kotlin/insight/ListenerLineMarkerProvider.kt b/src/main/kotlin/insight/ListenerLineMarkerProvider.kt index 3b267b053..8fbb53a7c 100644 --- a/src/main/kotlin/insight/ListenerLineMarkerProvider.kt +++ b/src/main/kotlin/insight/ListenerLineMarkerProvider.kt @@ -25,11 +25,13 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.PsiExpression import com.intellij.psi.PsiFunctionalExpression -import com.intellij.psi.PsiMethod import com.intellij.psi.util.PsiExpressionTrimRenderer import com.intellij.psi.util.PsiUtilCore import com.intellij.util.Function import javax.swing.Icon +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UMethod +import org.jetbrains.uast.toUElementOfType /** * A [LineMarkerProviderDescriptor] that will provide a line marker info icon @@ -43,7 +45,7 @@ class ListenerLineMarkerProvider : LineMarkerProviderDescriptor() { return null } - val listener = element.eventListener ?: return null + val listener = element.toUElementOfType()?.uastEventListener ?: return null // By this point, we can guarantee that the action of "go to declaration" will work // since the PsiClass can be resolved, meaning the event listener is listening to // a valid event. @@ -57,19 +59,19 @@ class ListenerLineMarkerProvider : LineMarkerProviderDescriptor() { // This is a navigation handler that just simply goes and opens up the event's declaration, // even if the event target is a nested class. - private fun createHandler(method: PsiMethod): GutterIconNavigationHandler { - return GutterIconNavigationHandler handler@{ _, element1 -> + private fun createHandler(method: UMethod): GutterIconNavigationHandler { + return GutterIconNavigationHandler handler@{ _, element -> // We need to re-evaluate the targeted method, because if the method signature slightly changes before // IntelliJ decides to re-evaluate the method, but the class is no longer valid. // In this circumstance, we can find the class anyways because it's still a valid listener. - val containingFile = element1.containingFile - val parameter = method.eventParameterPair ?: return@handler + val containingFile = element.containingFile ?: return@handler + val parameter = method.uastEventParameterPair ?: return@handler - val resolve = parameter.second + val resolve = parameter.second.sourcePsi ?: return@handler val virtualFile = PsiUtilCore.getVirtualFile(resolve) - if (virtualFile != null && containingFile != null) { - val project = method.project + if (virtualFile != null) { + val project = element.project val editor = FileEditorManager.getInstance(project).selectedTextEditor if (editor != null) { diff --git a/src/main/kotlin/platform/adventure/color/AdventureColorLineMarkerProvider.kt b/src/main/kotlin/platform/adventure/color/AdventureColorLineMarkerProvider.kt index f46623ce1..b51eeef01 100644 --- a/src/main/kotlin/platform/adventure/color/AdventureColorLineMarkerProvider.kt +++ b/src/main/kotlin/platform/adventure/color/AdventureColorLineMarkerProvider.kt @@ -13,7 +13,8 @@ package com.demonwav.mcdev.platform.adventure.color import com.demonwav.mcdev.insight.ColorLineMarkerProvider import com.intellij.psi.PsiElement import java.awt.Color +import org.jetbrains.uast.UElement class AdventureColorLineMarkerProvider : ColorLineMarkerProvider.CommonLineMarkerProvider() { - override fun findColor(element: PsiElement): Pair? = element.findAdventureColor() + override fun findColor(element: PsiElement): Pair? = element.findAdventureColor() } diff --git a/src/main/kotlin/platform/adventure/color/AdventureColorUtil.kt b/src/main/kotlin/platform/adventure/color/AdventureColorUtil.kt index 1577f3375..096f5ef63 100644 --- a/src/main/kotlin/platform/adventure/color/AdventureColorUtil.kt +++ b/src/main/kotlin/platform/adventure/color/AdventureColorUtil.kt @@ -15,6 +15,9 @@ import com.demonwav.mcdev.platform.adventure.AdventureConstants import com.demonwav.mcdev.platform.adventure.AdventureModuleType import com.intellij.psi.PsiElement import java.awt.Color +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType -fun PsiElement.findAdventureColor(): Pair? = - findColor(AdventureModuleType, AdventureConstants.TEXT_COLOR_CLASS, null) +fun PsiElement.findAdventureColor(): Pair? = + this.toUElementOfType()?.findColor(AdventureModuleType, AdventureConstants.TEXT_COLOR_CLASS, null) diff --git a/src/main/kotlin/platform/sponge/color/SpongeColorLineMarkerProvider.kt b/src/main/kotlin/platform/sponge/color/SpongeColorLineMarkerProvider.kt index 2fcab0e17..62670ffd5 100644 --- a/src/main/kotlin/platform/sponge/color/SpongeColorLineMarkerProvider.kt +++ b/src/main/kotlin/platform/sponge/color/SpongeColorLineMarkerProvider.kt @@ -13,7 +13,8 @@ package com.demonwav.mcdev.platform.sponge.color import com.demonwav.mcdev.insight.ColorLineMarkerProvider import com.intellij.psi.PsiElement import java.awt.Color +import org.jetbrains.uast.UElement class SpongeColorLineMarkerProvider : ColorLineMarkerProvider.CommonLineMarkerProvider() { - override fun findColor(element: PsiElement): Pair? = element.findSpongeColor() + override fun findColor(element: PsiElement): Pair? = element.findSpongeColor() } diff --git a/src/main/kotlin/platform/sponge/color/SpongeColorUtil.kt b/src/main/kotlin/platform/sponge/color/SpongeColorUtil.kt index c478d6780..51b128672 100644 --- a/src/main/kotlin/platform/sponge/color/SpongeColorUtil.kt +++ b/src/main/kotlin/platform/sponge/color/SpongeColorUtil.kt @@ -14,9 +14,12 @@ import com.demonwav.mcdev.insight.findColor import com.demonwav.mcdev.platform.sponge.SpongeModuleType import com.intellij.psi.PsiElement import java.awt.Color +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType -fun PsiElement.findSpongeColor(): Pair? = - findColor( +fun PsiElement.findSpongeColor(): Pair? = + this.toUElementOfType()?.findColor( SpongeModuleType, "org.spongepowered.api.util.Color", arrayOf( diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 52f1f3b61..e8179cc3b 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -68,8 +68,8 @@ - - + + @@ -176,7 +176,7 @@ - + From 13f73067419453f5d8ac4bfc660d3fe85ecea4b2 Mon Sep 17 00:00:00 2001 From: RedNesto Date: Wed, 30 Dec 2020 11:55:58 +0100 Subject: [PATCH 2/5] Port Plugin line marker to UAST --- .../kotlin/platform/bukkit/BukkitModule.kt | 29 ++++++++----------- .../platform/bukkit/util/BukkitConstants.kt | 2 +- .../platform/bungeecord/BungeeCordModule.kt | 26 ++++++++--------- .../kotlin/platform/fabric/FabricModule.kt | 19 +++++++----- src/main/kotlin/platform/forge/ForgeModule.kt | 21 +++++++------- .../platform/liteloader/LiteLoaderModule.kt | 13 +++++---- .../kotlin/platform/sponge/SpongeModule.kt | 21 +++++++------- .../platform/velocity/VelocityModule.kt | 17 +++++++---- src/main/resources/META-INF/plugin.xml | 2 +- 9 files changed, 77 insertions(+), 73 deletions(-) diff --git a/src/main/kotlin/platform/bukkit/BukkitModule.kt b/src/main/kotlin/platform/bukkit/BukkitModule.kt index c42d0eea0..d8cc26080 100644 --- a/src/main/kotlin/platform/bukkit/BukkitModule.kt +++ b/src/main/kotlin/platform/bukkit/BukkitModule.kt @@ -23,18 +23,20 @@ import com.demonwav.mcdev.util.addImplements import com.demonwav.mcdev.util.extendsOrImplements import com.demonwav.mcdev.util.findContainingMethod import com.demonwav.mcdev.util.nullable +import com.intellij.lang.jvm.JvmModifier import com.intellij.openapi.project.Project import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassType import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiLiteralExpression import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiType import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.util.PsiTypesUtil +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType class BukkitModule> constructor(facet: MinecraftFacet, type: T) : AbstractModule(facet) { @@ -153,24 +155,17 @@ class BukkitModule> constructor(facet: MinecraftFa } override fun shouldShowPluginIcon(element: PsiElement?): Boolean { - if (element !is PsiIdentifier) { - return false - } + val identifier = element?.toUElementOfType() + ?: return false - if (element.parent !is PsiClass) { - return false - } + val psiClass = (identifier.uastParent as? UClass)?.javaPsi + ?: return false - val project = element.project - val psiClass = element.parent as PsiClass - val javaPluginClass = JavaPsiFacade.getInstance(project) - .findClass(BukkitConstants.JAVA_PLUGIN, GlobalSearchScope.allScope(project)) + val pluginInterface = JavaPsiFacade.getInstance(element.project) + .findClass(BukkitConstants.PLUGIN, module.getModuleWithDependenciesAndLibrariesScope(false)) + ?: return false - return javaPluginClass != null && psiClass.extendsListTypes.any { c -> - c == PsiTypesUtil.getClassType( - javaPluginClass - ) - } + return !psiClass.hasModifier(JvmModifier.ABSTRACT) && psiClass.isInheritor(pluginInterface, true) } override fun dispose() { diff --git a/src/main/kotlin/platform/bukkit/util/BukkitConstants.kt b/src/main/kotlin/platform/bukkit/util/BukkitConstants.kt index 97595fe3f..9da4d296f 100644 --- a/src/main/kotlin/platform/bukkit/util/BukkitConstants.kt +++ b/src/main/kotlin/platform/bukkit/util/BukkitConstants.kt @@ -17,7 +17,7 @@ object BukkitConstants { const val LISTENER_CLASS = "org.bukkit.event.Listener" const val CHAT_COLOR_CLASS = "org.bukkit.ChatColor" const val EVENT_CLASS = "org.bukkit.event.Event" - const val JAVA_PLUGIN = "org.bukkit.plugin.java.JavaPlugin" + const val PLUGIN = "org.bukkit.plugin.Plugin" const val EVENT_ISCANCELLED_METHOD_NAME = "isCancelled" const val CANCELLABLE_CLASS = "org.bukkit.event.Cancellable" } diff --git a/src/main/kotlin/platform/bungeecord/BungeeCordModule.kt b/src/main/kotlin/platform/bungeecord/BungeeCordModule.kt index cd6f7443e..8118b5a30 100644 --- a/src/main/kotlin/platform/bungeecord/BungeeCordModule.kt +++ b/src/main/kotlin/platform/bungeecord/BungeeCordModule.kt @@ -25,13 +25,14 @@ import com.demonwav.mcdev.util.SourceType import com.demonwav.mcdev.util.addImplements import com.demonwav.mcdev.util.extendsOrImplements import com.demonwav.mcdev.util.nullable +import com.intellij.lang.jvm.JvmModifier import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.util.PsiTypesUtil +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType class BungeeCordModule>(facet: MinecraftFacet, type: T) : AbstractModule(facet) { @@ -103,20 +104,17 @@ class BungeeCordModule>(facet: MinecraftFacet, typ } override fun shouldShowPluginIcon(element: PsiElement?): Boolean { - if (element !is PsiIdentifier) { - return false - } + val identifier = element?.toUElementOfType() + ?: return false - if (element.parent !is PsiClass) { - return false - } + val psiClass = (identifier.uastParent as? UClass)?.javaPsi + ?: return false - val project = element.project - val psiClass = element.parent as PsiClass - val pluginClass = JavaPsiFacade.getInstance(project) - .findClass(BungeeCordConstants.PLUGIN, GlobalSearchScope.allScope(project)) + val pluginInterface = JavaPsiFacade.getInstance(element.project) + .findClass(BungeeCordConstants.PLUGIN, module.getModuleWithDependenciesAndLibrariesScope(false)) + ?: return false - return pluginClass != null && psiClass.extendsListTypes.any { c -> c == PsiTypesUtil.getClassType(pluginClass) } + return !psiClass.hasModifier(JvmModifier.ABSTRACT) && psiClass.isInheritor(pluginInterface, true) } override fun dispose() { diff --git a/src/main/kotlin/platform/fabric/FabricModule.kt b/src/main/kotlin/platform/fabric/FabricModule.kt index af0465705..8dd25e9b7 100644 --- a/src/main/kotlin/platform/fabric/FabricModule.kt +++ b/src/main/kotlin/platform/fabric/FabricModule.kt @@ -20,9 +20,12 @@ import com.demonwav.mcdev.util.SourceType import com.demonwav.mcdev.util.nullable import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod import com.intellij.psi.search.searches.ReferencesSearch +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UMethod +import org.jetbrains.uast.toUElementOfType class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(facet) { @@ -38,15 +41,17 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule( override fun writeErrorMessageForEventParameter(eventClass: PsiClass, method: PsiMethod) = "" override fun shouldShowPluginIcon(element: PsiElement?): Boolean { - if (element !is PsiIdentifier) { - return false - } - val parent = element.parent - if (parent !is PsiClass && parent !is PsiMethod) { + val identifier = element?.toUElementOfType() + ?: return false + + val parent = identifier.uastParent + if (parent !is UClass && parent !is UMethod) { return false } - return ReferencesSearch.search(parent).anyMatch { EntryPointReference.isEntryPointReference(it) } + val psiParent = parent.sourcePsi + ?: return false + return ReferencesSearch.search(psiParent).anyMatch { EntryPointReference.isEntryPointReference(it) } } override fun dispose() { diff --git a/src/main/kotlin/platform/forge/ForgeModule.kt b/src/main/kotlin/platform/forge/ForgeModule.kt index d4c5c5819..763da2cb3 100644 --- a/src/main/kotlin/platform/forge/ForgeModule.kt +++ b/src/main/kotlin/platform/forge/ForgeModule.kt @@ -26,6 +26,7 @@ import com.demonwav.mcdev.util.nullable import com.demonwav.mcdev.util.runWriteTaskLater import com.demonwav.mcdev.util.waitForAllSmart import com.intellij.json.JsonFileType +import com.intellij.lang.jvm.JvmModifier import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.fileTypes.FileTypeManager import com.intellij.openapi.project.DumbService @@ -33,12 +34,14 @@ import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassType import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiType import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.searches.AnnotatedElementsSearch +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType class ForgeModule internal constructor(facet: MinecraftFacet) : AbstractModule(facet) { @@ -178,18 +181,14 @@ class ForgeModule internal constructor(facet: MinecraftFacet) : AbstractModule(f } override fun shouldShowPluginIcon(element: PsiElement?): Boolean { - if (element !is PsiIdentifier) { - return false - } - - if (element.parent !is PsiClass) { - return false - } + val identifier = element?.toUElementOfType() + ?: return false - val psiClass = element.parent as PsiClass + val psiClass = identifier.uastParent as? UClass + ?: return false - val modifierList = psiClass.modifierList - return modifierList?.findAnnotation(ForgeConstants.MOD_ANNOTATION) != null + return !psiClass.hasModifier(JvmModifier.ABSTRACT) && + psiClass.findAnnotation(ForgeConstants.MOD_ANNOTATION) != null } override fun checkUselessCancelCheck(expression: PsiMethodCallExpression): IsCancelled? = null diff --git a/src/main/kotlin/platform/liteloader/LiteLoaderModule.kt b/src/main/kotlin/platform/liteloader/LiteLoaderModule.kt index 9b2fc7cba..e0b40b363 100644 --- a/src/main/kotlin/platform/liteloader/LiteLoaderModule.kt +++ b/src/main/kotlin/platform/liteloader/LiteLoaderModule.kt @@ -19,8 +19,10 @@ import com.demonwav.mcdev.util.SourceType import com.demonwav.mcdev.util.nullable import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType class LiteLoaderModule internal constructor(facet: MinecraftFacet) : AbstractModule(facet) { @@ -35,10 +37,11 @@ class LiteLoaderModule internal constructor(facet: MinecraftFacet) : AbstractMod override fun writeErrorMessageForEventParameter(eventClass: PsiClass, method: PsiMethod) = "" - override fun shouldShowPluginIcon(element: PsiElement?) = - element is PsiIdentifier && - element.parent is PsiClass && - element.text.startsWith("LiteMod") + override fun shouldShowPluginIcon(element: PsiElement?): Boolean { + val identifier = element?.toUElementOfType() + ?: return false + return identifier.uastParent is UClass && identifier.name.startsWith("LiteMod") + } override fun dispose() { super.dispose() diff --git a/src/main/kotlin/platform/sponge/SpongeModule.kt b/src/main/kotlin/platform/sponge/SpongeModule.kt index 684bdee3a..b67139b0a 100644 --- a/src/main/kotlin/platform/sponge/SpongeModule.kt +++ b/src/main/kotlin/platform/sponge/SpongeModule.kt @@ -20,16 +20,19 @@ import com.demonwav.mcdev.platform.sponge.generation.SpongeGenerationData import com.demonwav.mcdev.platform.sponge.util.SpongeConstants import com.demonwav.mcdev.util.extendsOrImplements import com.demonwav.mcdev.util.findContainingMethod +import com.intellij.lang.jvm.JvmModifier import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiAnnotationMemberValue import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassType import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiType import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType class SpongeModule(facet: MinecraftFacet) : AbstractModule(facet) { @@ -89,18 +92,14 @@ class SpongeModule(facet: MinecraftFacet) : AbstractModule(facet) { } override fun shouldShowPluginIcon(element: PsiElement?): Boolean { - if (element !is PsiIdentifier) { - return false - } - - if (element.parent !is PsiClass) { - return false - } + val identifier = element?.toUElementOfType() + ?: return false - val psiClass = element.parent as PsiClass + val psiClass = identifier.uastParent as? UClass + ?: return false - val modifierList = psiClass.modifierList - return modifierList?.findAnnotation(SpongeConstants.PLUGIN_ANNOTATION) != null + return !psiClass.hasModifier(JvmModifier.ABSTRACT) && + psiClass.findAnnotation(SpongeConstants.PLUGIN_ANNOTATION) != null } override fun checkUselessCancelCheck(expression: PsiMethodCallExpression): IsCancelled? { diff --git a/src/main/kotlin/platform/velocity/VelocityModule.kt b/src/main/kotlin/platform/velocity/VelocityModule.kt index d27e2e91f..38a5ea586 100644 --- a/src/main/kotlin/platform/velocity/VelocityModule.kt +++ b/src/main/kotlin/platform/velocity/VelocityModule.kt @@ -18,14 +18,17 @@ import com.demonwav.mcdev.platform.PlatformType import com.demonwav.mcdev.platform.velocity.generation.VelocityGenerationData import com.demonwav.mcdev.platform.velocity.util.VelocityConstants import com.demonwav.mcdev.platform.velocity.util.VelocityConstants.SUBSCRIBE_ANNOTATION +import com.intellij.lang.jvm.JvmModifier import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassType import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod import com.intellij.psi.PsiType import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElementOfType class VelocityModule(facet: MinecraftFacet) : AbstractModule(facet) { override val moduleType = VelocityModuleType @@ -71,11 +74,13 @@ class VelocityModule(facet: MinecraftFacet) : AbstractModule(facet) { } override fun shouldShowPluginIcon(element: PsiElement?): Boolean { - if (element !is PsiIdentifier) { - return false - } + val identifier = element?.toUElementOfType() + ?: return false + + val psiClass = identifier.uastParent as? UClass + ?: return false - val psiClass = element.parent as? PsiClass ?: return false - return psiClass.hasAnnotation(VelocityConstants.PLUGIN_ANNOTATION) + return !psiClass.hasModifier(JvmModifier.ABSTRACT) && + psiClass.findAnnotation(VelocityConstants.PLUGIN_ANNOTATION) != null } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index e8179cc3b..324c2678f 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -65,7 +65,7 @@ - + From a5ed1ef471f151c674fb37af95a5a32fe0dc4497 Mon Sep 17 00:00:00 2001 From: RedNesto Date: Wed, 30 Dec 2020 14:44:08 +0100 Subject: [PATCH 3/5] Fix occasional invalid listener annotation range --- src/main/kotlin/insight/ListenerEventAnnotator.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/insight/ListenerEventAnnotator.kt b/src/main/kotlin/insight/ListenerEventAnnotator.kt index 3019de70e..2a6196de6 100644 --- a/src/main/kotlin/insight/ListenerEventAnnotator.kt +++ b/src/main/kotlin/insight/ListenerEventAnnotator.kt @@ -80,12 +80,10 @@ class ListenerEventAnnotator : Annotator { return } - if (!instance.isStaticListenerSupported(method.javaPsi) && method.isStatic) { - method.javaPsi.nameIdentifier?.let { - holder.newAnnotation(HighlightSeverity.ERROR, "Event listener method must not be static") - .range(it) - .create() - } + if (method.isStatic && element.toUElement()?.uastParent is UMethod && + !instance.isStaticListenerSupported(method.javaPsi) + ) { + holder.newAnnotation(HighlightSeverity.ERROR, "Event listener method must not be static").create() } if (element.getUastParentOfType()?.sourcePsi == eventParameter.sourcePsi && From ddec3a19b545803ea0fb949f0e5f337dfcea2518 Mon Sep 17 00:00:00 2001 From: RedNesto Date: Wed, 30 Dec 2020 15:02:22 +0100 Subject: [PATCH 4/5] Provide ColorPicker only the current color class --- src/main/kotlin/insight/ColorUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/insight/ColorUtil.kt b/src/main/kotlin/insight/ColorUtil.kt index 5b33cc173..aa98533e4 100644 --- a/src/main/kotlin/insight/ColorUtil.kt +++ b/src/main/kotlin/insight/ColorUtil.kt @@ -48,7 +48,7 @@ fun UIdentifier.findColor(function: (Map, Map.Entry key.startsWith(colorClass) }, entry) } } } From 5c0ac42edfeb1f078675876d3f7fc6f3e81acf64 Mon Sep 17 00:00:00 2001 From: RedNesto Date: Sat, 10 Apr 2021 09:38:15 +0200 Subject: [PATCH 5/5] Fix ktlint violation --- src/main/kotlin/insight/InsightUtil.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/insight/InsightUtil.kt b/src/main/kotlin/insight/InsightUtil.kt index adf0c7663..0b577d85f 100644 --- a/src/main/kotlin/insight/InsightUtil.kt +++ b/src/main/kotlin/insight/InsightUtil.kt @@ -57,6 +57,7 @@ val UMethod.uastEventParameterPair: Pair? val firstParameter = this.uastParameters.firstOrNull() ?: return null // Listeners must have at least a single parameter // Get the type of the parameter so we can start resolving it + @Suppress("UElementAsPsi") // UVariable overrides getType so it should be fine to use on UElements... val type = firstParameter.type as? PsiClassType ?: return null // Validate that it is a class reference type