Skip to content

Commit 9bb119b

Browse files
committed
Add inspection for hard SideOnly usage
1 parent a3fbaac commit 9bb119b

File tree

3 files changed

+118
-46
lines changed

3 files changed

+118
-46
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Minecraft Dev for IntelliJ
3+
*
4+
* https://minecraftdev.org
5+
*
6+
* Copyright (c) 2020 minecraft-dev
7+
*
8+
* MIT License
9+
*/
10+
11+
package com.demonwav.mcdev.sideonly
12+
13+
import com.intellij.codeInspection.ProblemDescriptor
14+
import com.intellij.openapi.project.Project
15+
import com.intellij.psi.JavaPsiFacade
16+
import com.intellij.psi.PsiAnnotation
17+
import com.intellij.psi.SmartPointerManager
18+
import com.intellij.psi.SmartPsiElementPointer
19+
import com.intellij.psi.codeStyle.JavaCodeStyleManager
20+
import com.siyeh.ig.BaseInspection
21+
import com.siyeh.ig.BaseInspectionVisitor
22+
import com.siyeh.ig.InspectionGadgetsFix
23+
24+
class HardSideOnlyUsageInspection : BaseInspection() {
25+
override fun getDisplayName(): String {
26+
return "Usage of hard-SideOnly annotations"
27+
}
28+
29+
override fun getStaticDescription(): String {
30+
return "Usage of hard-SideOnly annotations"
31+
}
32+
33+
override fun buildErrorString(vararg infos: Any?): String {
34+
return "Usage of @${infos[0] as String}"
35+
}
36+
37+
override fun buildVisitor(): BaseInspectionVisitor {
38+
return Visitor()
39+
}
40+
41+
override fun buildFix(vararg infos: Any?): InspectionGadgetsFix {
42+
return Fix(SmartPointerManager.createPointer(infos[1] as PsiAnnotation))
43+
}
44+
45+
private class Visitor : BaseInspectionVisitor() {
46+
override fun visitAnnotation(annotation: PsiAnnotation) {
47+
if (SideOnlyUtil.getAnnotationSide(annotation, SideHardness.HARD) != Side.BOTH) {
48+
registerError(
49+
annotation.navigationElement,
50+
annotation.nameReferenceElement?.text ?: annotation.qualifiedName,
51+
annotation
52+
)
53+
}
54+
}
55+
}
56+
57+
private class Fix(private val annotation: SmartPsiElementPointer<PsiAnnotation>) : InspectionGadgetsFix() {
58+
override fun doFix(project: Project, descriptor: ProblemDescriptor) {
59+
val annotation = this.annotation.element ?: return
60+
val oldSide = SideOnlyUtil.getAnnotationSide(annotation, SideHardness.HARD)
61+
val newAnnotation = JavaPsiFacade.getElementFactory(project).createAnnotationFromText(
62+
"@${SideOnlyUtil.MCDEV_SIDEONLY_ANNOTATION}(${SideOnlyUtil.MCDEV_SIDE}.$oldSide)",
63+
annotation
64+
)
65+
val createdAnnotation = annotation.replace(newAnnotation)
66+
val codeStyleManager = JavaCodeStyleManager.getInstance(project)
67+
codeStyleManager.shortenClassReferences(createdAnnotation)
68+
createdAnnotation.containingFile?.let { codeStyleManager.optimizeImports(it) }
69+
}
70+
71+
override fun getName() = "Replace with @CheckEnv"
72+
73+
override fun getFamilyName() = name
74+
}
75+
}

src/main/kotlin/sideonly/SideOnlyUtil.kt

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import com.demonwav.mcdev.platform.fabric.util.FabricConstants
1616
import com.demonwav.mcdev.platform.forge.util.ForgeConstants
1717
import com.demonwav.mcdev.platform.mixin.util.isMixin
1818
import com.demonwav.mcdev.platform.mixin.util.mixinTargets
19-
import com.demonwav.mcdev.util.findAnnotation
2019
import com.demonwav.mcdev.util.findModule
2120
import com.demonwav.mcdev.util.packageName
2221
import com.intellij.codeInspection.ProblemsHolder
@@ -25,6 +24,7 @@ import com.intellij.json.psi.JsonFile
2524
import com.intellij.json.psi.JsonObject
2625
import com.intellij.json.psi.JsonStringLiteral
2726
import com.intellij.psi.JavaPsiFacade
27+
import com.intellij.psi.PsiAnnotation
2828
import com.intellij.psi.PsiArrayType
2929
import com.intellij.psi.PsiClass
3030
import com.intellij.psi.PsiClassObjectAccessExpression
@@ -49,63 +49,53 @@ object SideOnlyUtil {
4949
const val MCDEV_SIDEONLY_ANNOTATION = "com.demonwav.mcdev.annotations.CheckEnv"
5050
const val MCDEV_SIDE = "com.demonwav.mcdev.annotations.Env"
5151

52-
internal fun getExplicitAnnotation(element: PsiModifierListOwner, hardness: SideHardness): SideInstance? {
52+
internal fun getAnnotationSide(annotation: PsiAnnotation, hardness: SideHardness): Side {
53+
var isSideAnnotation = false
54+
5355
if (hardness != SideHardness.HARD) {
54-
val mcDevAnnotation = element.findAnnotation(MCDEV_SIDEONLY_ANNOTATION)
55-
if (mcDevAnnotation != null) {
56-
val side = mcDevAnnotation.findAttributeValue("value") as? PsiReferenceExpression
57-
?: return null
58-
val sideConstant = side.resolve() as? PsiEnumConstant ?: return null
59-
return when (sideConstant.name) {
60-
"CLIENT" -> SideInstance.createMcDev(Side.CLIENT, element)
61-
"SERVER" -> SideInstance.createMcDev(Side.SERVER, element)
62-
else -> null
63-
}
56+
if (annotation.hasQualifiedName(MCDEV_SIDEONLY_ANNOTATION)) {
57+
isSideAnnotation = true
6458
}
6559
}
6660

6761
if (hardness != SideHardness.SOFT) {
68-
val sideOnlyAnnotation = element.findAnnotation(ForgeConstants.SIDE_ONLY_ANNOTATION)
69-
if (sideOnlyAnnotation != null) {
70-
val side = sideOnlyAnnotation.findAttributeValue("value") as? PsiReferenceExpression
71-
?: return null
72-
val sideConstant = side.resolve() as? PsiEnumConstant ?: return null
73-
return when (sideConstant.name) {
74-
"CLIENT" -> SideInstance.createSideOnly(Side.CLIENT, element)
75-
"SERVER" -> SideInstance.createSideOnly(Side.SERVER, element)
76-
else -> null
62+
if (annotation.hasQualifiedName(ForgeConstants.SIDE_ONLY_ANNOTATION) ||
63+
annotation.hasQualifiedName(FabricConstants.ENVIRONMENT_ANNOTATION)
64+
) {
65+
isSideAnnotation = true
66+
} else if (annotation.hasQualifiedName(ForgeConstants.ONLY_IN_ANNOTATION)) {
67+
if (annotation.findAttributeValue("_interface") != null) {
68+
isSideAnnotation = true
7769
}
7870
}
71+
}
7972

80-
val environmentAnnotation = element.findAnnotation(FabricConstants.ENVIRONMENT_ANNOTATION)
81-
if (environmentAnnotation != null) {
82-
val env = environmentAnnotation.findAttributeValue("value") as? PsiReferenceExpression
83-
?: return null
84-
val envConstant = env.resolve() as? PsiEnumConstant ?: return null
85-
return when (envConstant.name) {
86-
"CLIENT" -> SideInstance.createEnvironment(Side.CLIENT, element)
87-
"SERVER" -> SideInstance.createEnvironment(Side.SERVER, element)
88-
else -> null
89-
}
90-
}
73+
if (!isSideAnnotation) {
74+
return Side.BOTH
75+
}
9176

92-
val onlyInAnnotation = element.annotations.firstOrNull {
93-
it.hasQualifiedName(ForgeConstants.ONLY_IN_ANNOTATION) &&
94-
it.findAttributeValue("_interface") == null
95-
}
96-
if (onlyInAnnotation != null) {
97-
val dist = onlyInAnnotation.findAttributeValue("value") as? PsiReferenceExpression
98-
?: return null
99-
val distConstant = dist.resolve() as? PsiEnumConstant ?: return null
100-
return when (distConstant.name) {
101-
"CLIENT" -> SideInstance.createOnlyIn(Side.CLIENT, element)
102-
"DEDICATED_SERVER" -> SideInstance.createOnlyIn(Side.SERVER, element)
77+
val side = annotation.findAttributeValue("value") as? PsiReferenceExpression ?: return Side.BOTH
78+
val sideConstant = side.resolve() as? PsiEnumConstant ?: return Side.BOTH
79+
return when (sideConstant.name) {
80+
"CLIENT" -> Side.CLIENT
81+
"SERVER", "DEDICATED_SERVER" -> Side.SERVER
82+
else -> Side.BOTH
83+
}
84+
}
85+
86+
internal fun getExplicitAnnotation(element: PsiModifierListOwner, hardness: SideHardness): SideInstance? {
87+
return element.annotations.asSequence()
88+
.map { it to getAnnotationSide(it, hardness) }
89+
.firstOrNull { it.second != Side.BOTH }
90+
?.let {
91+
when (it.first.qualifiedName) {
92+
MCDEV_SIDEONLY_ANNOTATION -> SideInstance.createMcDev(it.second, element)
93+
ForgeConstants.SIDE_ONLY_ANNOTATION -> SideInstance.createSideOnly(it.second, element)
94+
ForgeConstants.ONLY_IN_ANNOTATION -> SideInstance.createOnlyIn(it.second, element)
95+
FabricConstants.ENVIRONMENT_ANNOTATION -> SideInstance.createEnvironment(it.second, element)
10396
else -> null
10497
}
10598
}
106-
}
107-
108-
return null
10999
}
110100

111101
internal fun getExplicitOrInferredAnnotation(element: PsiModifierListOwner, hardness: SideHardness): SideInstance? {

src/main/resources/META-INF/plugin.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,13 @@
330330
level="WARNING"
331331
hasStaticDescription="true"
332332
implementationClass="com.demonwav.mcdev.sideonly.SideOnlyInspection"/>
333+
<localInspection displayName="Usage of hard-SideOnly annotations"
334+
groupName="Minecraft"
335+
language="JAVA"
336+
enabledByDefault="true"
337+
level="WARNING"
338+
hasStaticDescription="true"
339+
implementationClass="com.demonwav.mcdev.sideonly.HardSideOnlyUsageInspection"/>
333340
<!--endregion-->
334341

335342
<!--region BUKKIT INSPECTIONS-->

0 commit comments

Comments
 (0)