Skip to content

Commit

Permalink
Merge pull request #306 from guymahieu/feature/support-inherited-acce…
Browse files Browse the repository at this point in the history
…ssors

[#307] Axon plugin gives false highlights about non existing properties when they are defined in a superclass
  • Loading branch information
CodeDrivenMitch authored Oct 14, 2024
2 parents 781f71c + 4f77d7c commit 114c4af
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class JavaSagaAssociationPropertyInspection : AbstractBaseJavaLocalInspectionToo
return null
val payload = method.resolvePayloadType() ?: return null
val payloadClass = method.project.toClass(payload) ?: return null
if (payloadClass.hasAccessor(attribute)) {
if (payloadClass.hasAccessor(attribute, true)) {
return null
}
val annotation = method.resolveAnnotation(AxonAnnotation.SAGA_EVENT_HANDLER) ?: return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class KotlinSagaAssociationPropertyInspection : AbstractKotlinInspection() {
return
val payload = method.resolvePayloadType() ?: return
val payloadClass = method.project.toClass(payload) ?: return
if (payloadClass.hasAccessor(attribute)) {
if (payloadClass.hasAccessor(attribute, true)) {
return
}
val annotation = method.resolveAnnotation(AxonAnnotation.SAGA_EVENT_HANDLER) ?: return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,32 @@ fun Project.toClass(type: PsiType, scope: GlobalSearchScope = this.axonScope()):
/**
* Checks whether the PsiClass has an accessor with that name. That means either a field, or a function with getter-style naming
*/
fun PsiClass.hasAccessor(name: String): Boolean = this.getAccessor(name) != null
fun PsiClass.hasAccessor(name: String, scanHierarchy: Boolean = false): Boolean = this.getAccessor(name, scanHierarchy) != null

/**
* Gets the PsiElement representing an accessor with that name. That means either a field, or a function with getter-style naming
* Will traverse the class hierarchy if true is passed as value for the scanHierarchy parameter
*/
fun PsiClass.getAccessor(name: String): PsiElement? {
return fields.firstOrNull { it.name == name } ?: methods.firstOrNull { it.name == name.toGetterRepresentation() }
fun PsiClass.getAccessor(name: String, scanHierarchy: Boolean = false): PsiElement? {
return getAccessorImpl(name, scanHierarchy)
}

private fun PsiClass.getAccessorImpl(name: String, scanHierarchy: Boolean = false): PsiElement? {
val foundField = fields.firstOrNull { it.name == name }
if (foundField != null) {
return foundField
}
val foundMethod = methods.firstOrNull { it.name == name.toGetterRepresentation() }
if (foundMethod != null) {
return foundMethod
}
if (scanHierarchy && superClass != null) {
val fromSuperclass = superClass?.getAccessorImpl(name, true)
if (fromSuperclass != null) {
return fromSuperclass
}
}
return null
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class JavaSagaAssociationPropertyInspectionTest : AbstractAxonFixtureTestCase()
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.text == "handle" && it.description.contains("The message does not declare a property")
it.description.contains("The message does not declare a property")
}
}

Expand All @@ -100,7 +100,40 @@ class JavaSagaAssociationPropertyInspectionTest : AbstractAxonFixtureTestCase()
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.text == "handle" && it.description.contains("The message does not declare a property")
it.description.contains("The message does not declare a property")
}
}

fun `test should detect defined property in superclass`() {
addFile(
"MyBaseMessage.java", """
public abstract class MyBaseMessage {
String some;
}
""".trimIndent()
)
addFile(
"MyMessage.java", """
public class MyMessage extends test.MyBaseMessage {
}
""".trimIndent()
)
val file = addFile(
"MyHandler.java", """
import test.MyMessage;
public class MyHandler {
@SagaEventHandler(associationProperty = "some")
public void handle(MyMessage message) {}
}
""".trimIndent()
)

myFixture.enableInspections(JavaSagaAssociationPropertyInspection())
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.description.contains("The message does not declare a property")
}
}

Expand Down Expand Up @@ -129,7 +162,42 @@ class JavaSagaAssociationPropertyInspectionTest : AbstractAxonFixtureTestCase()
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.text == "handle" && it.description.contains("The message does not declare a property")
it.description.contains("The message does not declare a property")
}
}

fun `test should detect defined getter in superclass`() {
addFile(
"MyBaseMessage.java", """
public abstract class MyBaseMessage {
String getSome() {
return "";
}
}
""".trimIndent()
)
addFile(
"MyMessage.java", """
public class MyMessage extends test.MyBaseMessage {
}
""".trimIndent()
)
val file = addFile(
"MyHandler.java", """
import test.MyMessage;
public class MyHandler {
@SagaEventHandler(associationProperty = "some")
public void handle(MyMessage message) {}
}
""".trimIndent()
)

myFixture.enableInspections(JavaSagaAssociationPropertyInspection())
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.description.contains("The message does not declare a property")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class KotlinSagaAssociationPropertyInspectionTest : AbstractAxonFixtureTestCase(
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.text == "handle" && it.description.contains("The message does not declare a property")
it.description.contains("The message does not declare a property")
}
}

Expand All @@ -77,7 +77,29 @@ class KotlinSagaAssociationPropertyInspectionTest : AbstractAxonFixtureTestCase(
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.text == "handle" && it.description.contains("The message does not declare a property")
it.description.contains("The message does not declare a property")
}
}

fun `test detect defined property in superclass`() {
val file = addFile(
"file.kt", """
open class MyBaseMessage(open val some: String)
open class MyMessage() : MyBaseMessage("")
class MyHandler {
@SagaEventHandler(associationProperty = "some")
fun handle(message: MyMessage) {}
}
""".trimIndent()
)

myFixture.enableInspections(KotlinSagaAssociationPropertyInspection())
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.description.contains("The message does not declare a property")
}
}

Expand All @@ -99,7 +121,31 @@ class KotlinSagaAssociationPropertyInspectionTest : AbstractAxonFixtureTestCase(
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.text == "handle" && it.description.contains("The message does not declare a property")
it.description.contains("The message does not declare a property")
}
}

fun `test detect defined getter in superclass`() {
val file = addFile(
"file.kt", """
open class MyBaseMessage() {
fun getSome() = ""
}
open class MyMessage : MyBaseMessage
class MyHandler {
@SagaEventHandler(associationProperty = "some")
fun handle(message: MyMessage) {}
}
""".trimIndent()
)

myFixture.enableInspections(KotlinSagaAssociationPropertyInspection())
myFixture.openFileInEditor(file)
val highlights = myFixture.doHighlighting(HighlightSeverity.WARNING)
Assertions.assertThat(highlights).noneMatch {
it.description.contains("The message does not declare a property")
}
}
}

0 comments on commit 114c4af

Please sign in to comment.