Skip to content

Commit 9ab87fb

Browse files
committed
Add warning for mixin added enum constants not prefixed by the mod ID
1 parent 7a5d859 commit 9ab87fb

15 files changed

Lines changed: 380 additions & 79 deletions

File tree

src/main/kotlin/platform/AbstractModule.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@ import com.demonwav.mcdev.facet.MinecraftFacet
2424
import com.demonwav.mcdev.insight.generation.EventListenerGenerationSupport
2525
import com.demonwav.mcdev.inspection.IsCancelled
2626
import com.intellij.openapi.module.Module
27+
import com.intellij.openapi.util.Key
2728
import com.intellij.psi.PsiClass
2829
import com.intellij.psi.PsiElement
2930
import com.intellij.psi.PsiExpression
3031
import com.intellij.psi.PsiMethod
3132
import com.intellij.psi.PsiMethodCallExpression
3233
import com.intellij.psi.PsiReferenceExpression
34+
import com.intellij.psi.util.CachedValue
35+
import com.intellij.psi.util.CachedValueProvider
36+
import com.intellij.psi.util.CachedValuesManager
37+
import com.intellij.psi.util.PsiModificationTracker
3338
import javax.swing.Icon
3439

3540
abstract class AbstractModule(protected val facet: MinecraftFacet) {
@@ -44,6 +49,21 @@ abstract class AbstractModule(protected val facet: MinecraftFacet) {
4449
open val icon: Icon?
4550
get() = moduleType.icon
4651

52+
protected open fun computeModIds(): List<String> = emptyList()
53+
54+
private val modIdsCacheKey = Key.create<CachedValue<List<String>>>("modIds for ${javaClass.simpleName}")
55+
56+
/**
57+
* Returns a list of mod IDs for this module. Must be called in a read action!
58+
*/
59+
val modIds: List<String>
60+
get() {
61+
val provider = CachedValueProvider {
62+
CachedValueProvider.Result(computeModIds(), PsiModificationTracker.MODIFICATION_COUNT)
63+
}
64+
return CachedValuesManager.getManager(project).getCachedValue(module, modIdsCacheKey, provider, false)
65+
}
66+
4767
open val eventListenerGenSupport: EventListenerGenerationSupport? = null
4868

4969
/**

src/main/kotlin/platform/bukkit/BukkitModule.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,26 @@ import com.demonwav.mcdev.platform.PlatformType
2929
import com.demonwav.mcdev.platform.bukkit.util.BukkitConstants
3030
import com.demonwav.mcdev.platform.bukkit.util.PaperConstants
3131
import com.demonwav.mcdev.util.SourceType
32-
import com.demonwav.mcdev.util.createVoidMethodWithParameterType
3332
import com.demonwav.mcdev.util.extendsOrImplements
3433
import com.demonwav.mcdev.util.findContainingMethod
3534
import com.demonwav.mcdev.util.nullable
3635
import com.demonwav.mcdev.util.runCatchingKtIdeaExceptions
3736
import com.intellij.lang.jvm.JvmModifier
3837
import com.intellij.openapi.project.Project
38+
import com.intellij.openapi.vfs.VirtualFile
3939
import com.intellij.psi.JavaPsiFacade
4040
import com.intellij.psi.PsiClass
4141
import com.intellij.psi.PsiElement
4242
import com.intellij.psi.PsiLiteralExpression
43+
import com.intellij.psi.PsiManager
4344
import com.intellij.psi.PsiMethod
4445
import com.intellij.psi.PsiMethodCallExpression
4546
import com.intellij.util.application
4647
import org.jetbrains.uast.UClass
4748
import org.jetbrains.uast.UIdentifier
4849
import org.jetbrains.uast.toUElementOfType
50+
import org.jetbrains.yaml.YAMLUtil
51+
import org.jetbrains.yaml.psi.YAMLFile
4952

5053
class BukkitModule<out T : AbstractModuleType<*>>(facet: MinecraftFacet, type: T) : AbstractModule(facet) {
5154

@@ -66,6 +69,8 @@ class BukkitModule<out T : AbstractModuleType<*>>(facet: MinecraftFacet, type: T
6669

6770
override val type: PlatformType = type.platformType
6871

72+
override fun computeModIds() = getPluginNames(project, pluginYml)
73+
6974
override val moduleType: T = type
7075

7176
override val eventListenerGenSupport: EventListenerGenerationSupport = BukkitEventListenerGenerationSupport()
@@ -175,4 +180,12 @@ class BukkitModule<out T : AbstractModuleType<*>>(facet: MinecraftFacet, type: T
175180

176181
pluginYml = null
177182
}
183+
184+
companion object {
185+
fun getPluginNames(project: Project, pluginYml: VirtualFile?): List<String> {
186+
val yamlFile = PsiManager.getInstance(project).findFile(pluginYml ?: return emptyList()) as? YAMLFile
187+
?: return emptyList()
188+
return listOfNotNull(YAMLUtil.getValue(yamlFile, "name")?.second)
189+
}
190+
}
178191
}

src/main/kotlin/platform/bungeecord/BungeeCordModule.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.demonwav.mcdev.insight.generation.EventListenerGenerationSupport
2525
import com.demonwav.mcdev.platform.AbstractModule
2626
import com.demonwav.mcdev.platform.AbstractModuleType
2727
import com.demonwav.mcdev.platform.PlatformType
28+
import com.demonwav.mcdev.platform.bukkit.BukkitModule
2829
import com.demonwav.mcdev.platform.bukkit.BukkitModuleType
2930
import com.demonwav.mcdev.platform.bukkit.PaperModuleType
3031
import com.demonwav.mcdev.platform.bukkit.SpigotModuleType
@@ -65,6 +66,8 @@ class BungeeCordModule<out T : AbstractModuleType<*>>(facet: MinecraftFacet, typ
6566

6667
override val moduleType: T = type
6768

69+
override fun computeModIds() = BukkitModule.getPluginNames(project, pluginYml)
70+
6871
override val eventListenerGenSupport: EventListenerGenerationSupport = BungeeCordEventListenerGenerationSupport()
6972

7073
override fun isEventClassValid(eventClass: PsiClass, method: PsiMethod?) =

src/main/kotlin/platform/fabric/FabricModule.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ import com.demonwav.mcdev.platform.mcp.mappings.MappingsManager
3333
import com.demonwav.mcdev.util.SourceType
3434
import com.demonwav.mcdev.util.nullable
3535
import com.demonwav.mcdev.util.runCatchingKtIdeaExceptions
36+
import com.intellij.json.JsonUtil
37+
import com.intellij.json.psi.JsonFile
38+
import com.intellij.json.psi.JsonStringLiteral
3639
import com.intellij.psi.PsiClass
3740
import com.intellij.psi.PsiElement
41+
import com.intellij.psi.PsiManager
3842
import com.intellij.psi.PsiMethod
3943
import com.intellij.psi.search.searches.ReferencesSearch
4044
import java.io.IOException
@@ -64,6 +68,13 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(
6468
override val type = PlatformType.FABRIC
6569
override val icon = PlatformAssets.FABRIC_ICON
6670

71+
override fun computeModIds(): List<String> {
72+
val jsonFile = PsiManager.getInstance(project).findFile(fabricJson ?: return emptyList()) as? JsonFile
73+
?: return emptyList()
74+
val jsonObj = JsonUtil.getTopLevelObject(jsonFile) ?: return emptyList()
75+
return listOfNotNull((jsonObj.findProperty("id")?.value as? JsonStringLiteral)?.value)
76+
}
77+
6778
override fun isEventClassValid(eventClass: PsiClass, method: PsiMethod?) = true
6879

6980
override fun writeErrorMessageForEventParameter(eventClass: PsiClass, method: PsiMethod) = ""

src/main/kotlin/platform/forge/ForgeModule.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import com.demonwav.mcdev.platform.PlatformType
2929
import com.demonwav.mcdev.platform.forge.inspections.sideonly.SidedProxyAnnotator
3030
import com.demonwav.mcdev.platform.forge.util.ForgeConstants
3131
import com.demonwav.mcdev.platform.mcp.McpModuleSettings
32+
import com.demonwav.mcdev.toml.stringValue
3233
import com.demonwav.mcdev.util.SemanticVersion
3334
import com.demonwav.mcdev.util.SourceType
3435
import com.demonwav.mcdev.util.nullable
@@ -40,9 +41,12 @@ import com.intellij.lang.jvm.JvmModifier
4041
import com.intellij.openapi.application.ApplicationManager
4142
import com.intellij.openapi.application.ReadAction
4243
import com.intellij.openapi.fileTypes.FileTypeManager
44+
import com.intellij.openapi.project.Project
45+
import com.intellij.openapi.vfs.VirtualFile
4346
import com.intellij.psi.JavaPsiFacade
4447
import com.intellij.psi.PsiClass
4548
import com.intellij.psi.PsiElement
49+
import com.intellij.psi.PsiManager
4650
import com.intellij.psi.PsiMethod
4751
import com.intellij.psi.PsiMethodCallExpression
4852
import com.intellij.psi.search.GlobalSearchScope
@@ -52,16 +56,23 @@ import java.util.concurrent.Callable
5256
import org.jetbrains.uast.UClass
5357
import org.jetbrains.uast.UIdentifier
5458
import org.jetbrains.uast.toUElementOfType
59+
import org.toml.lang.psi.TomlArrayTable
60+
import org.toml.lang.psi.TomlFile
61+
import org.toml.lang.psi.ext.name
5562

5663
class ForgeModule internal constructor(facet: MinecraftFacet) : AbstractModule(facet) {
5764

5865
var mcmod by nullable { facet.findFile(ForgeConstants.MCMOD_INFO, SourceType.RESOURCE) }
5966
private set
67+
var modsToml by nullable { facet.findFile(ForgeConstants.MODS_TOML_PATH, SourceType.RESOURCE) }
68+
private set
6069

6170
override val moduleType = ForgeModuleType
6271
override val type = PlatformType.FORGE
6372
override val icon = PlatformAssets.FORGE_ICON
6473

74+
override fun computeModIds() = getModsFromModsToml(project, modsToml)
75+
6576
override val eventListenerGenSupport: EventListenerGenerationSupport = ForgeEventListenerGenerationSupport()
6677

6778
override fun init() {
@@ -168,6 +179,28 @@ class ForgeModule internal constructor(facet: MinecraftFacet) : AbstractModule(f
168179

169180
override fun dispose() {
170181
mcmod = null
182+
modsToml = null
171183
super.dispose()
172184
}
185+
186+
companion object {
187+
fun getModsFromModsToml(project: Project, modsToml: VirtualFile?): List<String> {
188+
val tomlFile = PsiManager.getInstance(project).findFile(modsToml ?: return emptyList()) as? TomlFile
189+
?: return emptyList()
190+
191+
val result = mutableListOf<String>()
192+
193+
for (child in tomlFile.children) {
194+
if (child is TomlArrayTable && child.header.key?.name == "mods") {
195+
for (entry in child.entries) {
196+
if (entry.key.name == "modId") {
197+
entry.value?.stringValue()?.let { result += it }
198+
}
199+
}
200+
}
201+
}
202+
203+
return result
204+
}
205+
}
173206
}

src/main/kotlin/platform/forge/util/ForgeConstants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ object ForgeConstants {
3737
const val NETWORK_MESSAGE_HANDLER = "net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler"
3838
const val MCMOD_INFO = "mcmod.info"
3939
const val MODS_TOML = "mods.toml"
40+
const val MODS_TOML_PATH = "META-INF/$MODS_TOML"
4041
const val PACK_MCMETA = "pack.mcmeta"
4142

4243
const val JAR_VERSION_VAR = $$"${file.jarVersion}"

src/main/kotlin/platform/mixin/inspection/addedMembers/AddedMembersNameFormatInspection.kt

Lines changed: 8 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@ package com.demonwav.mcdev.platform.mixin.inspection.addedMembers
2222

2323
import com.demonwav.mcdev.facet.MinecraftFacet
2424
import com.demonwav.mcdev.platform.fabric.FabricModuleType
25+
import com.demonwav.mcdev.util.RegexConverter
2526
import com.demonwav.mcdev.util.decapitalize
27+
import com.demonwav.mcdev.util.doBindItem
28+
import com.demonwav.mcdev.util.doBindText
2629
import com.demonwav.mcdev.util.findContainingClass
2730
import com.demonwav.mcdev.util.findModule
28-
import com.demonwav.mcdev.util.onShown
31+
import com.demonwav.mcdev.util.regexValidator
2932
import com.demonwav.mcdev.util.toJavaIdentifier
33+
import com.demonwav.mcdev.util.toRegexOrDefault
3034
import com.intellij.codeInsight.CodeInsightBundle
3135
import com.intellij.codeInsight.FileModificationService
3236
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
@@ -37,37 +41,24 @@ import com.intellij.ide.util.SuperMethodWarningUtil
3741
import com.intellij.openapi.editor.Editor
3842
import com.intellij.openapi.module.Module
3943
import com.intellij.openapi.project.Project
40-
import com.intellij.openapi.ui.ComboBox
41-
import com.intellij.openapi.ui.ComponentValidator
42-
import com.intellij.openapi.ui.DialogWrapper
4344
import com.intellij.openapi.util.text.StringUtil
4445
import com.intellij.psi.PsiElement
46+
import com.intellij.psi.PsiEnumConstant
4547
import com.intellij.psi.PsiField
4648
import com.intellij.psi.PsiFile
4749
import com.intellij.psi.PsiMethod
4850
import com.intellij.psi.PsiNameIdentifierOwner
4951
import com.intellij.psi.PsiNamedElement
5052
import com.intellij.psi.util.PsiTreeUtil
5153
import com.intellij.refactoring.rename.RenameProcessor
52-
import com.intellij.ui.DocumentAdapter
5354
import com.intellij.ui.EnumComboBoxModel
5455
import com.intellij.ui.components.JBLabel
55-
import com.intellij.ui.components.JBTextField
5656
import com.intellij.ui.dsl.builder.COLUMNS_SHORT
57-
import com.intellij.ui.dsl.builder.Cell
5857
import com.intellij.ui.dsl.builder.RowLayout
5958
import com.intellij.ui.dsl.builder.columns
6059
import com.intellij.ui.dsl.builder.panel
61-
import com.intellij.ui.layout.ValidationInfoBuilder
62-
import com.intellij.util.xmlb.Converter
6360
import com.intellij.util.xmlb.annotations.Attribute
64-
import java.util.function.Supplier
65-
import java.util.regex.Pattern
66-
import java.util.regex.PatternSyntaxException
6761
import javax.swing.JComponent
68-
import javax.swing.event.DocumentEvent
69-
import kotlin.reflect.KMutableProperty0
70-
import org.intellij.lang.annotations.Language
7162

7263
class AddedMembersNameFormatInspection : AbstractAddedMembersInspection() {
7364
@Attribute(converter = RegexConverter::class)
@@ -91,7 +82,7 @@ class AddedMembersNameFormatInspection : AbstractAddedMembersInspection() {
9182
override fun getStaticDescription() = "Reports added members not matching the correct name format"
9283

9384
override fun visitAddedField(holder: ProblemsHolder, field: PsiField) {
94-
if (reportFields.shouldReport(field.findModule())) {
85+
if (field !is PsiEnumConstant && reportFields.shouldReport(field.findModule())) {
9586
visitAdded(holder, field)
9687
}
9788
}
@@ -131,7 +122,7 @@ class AddedMembersNameFormatInspection : AbstractAddedMembersInspection() {
131122
val fixed = try {
132123
validNameFixSearch.replace(name, validNameFixReplace)
133124
.replace("MOD_ID", getAppropriatePrefix(holder.project))
134-
} catch (e: RuntimeException) {
125+
} catch (_: RuntimeException) {
135126
null
136127
}
137128

@@ -219,67 +210,6 @@ class AddedMembersNameFormatInspection : AbstractAddedMembersInspection() {
219210
}
220211
}
221212

222-
private fun String.toRegexOrDefault(@Language("RegExp") default: String): Regex {
223-
return try {
224-
this.toRegex()
225-
} catch (e: PatternSyntaxException) {
226-
default.toRegex()
227-
}
228-
}
229-
230-
private fun Cell<JBTextField>.doBindText(property: KMutableProperty0<String>): Cell<JBTextField> {
231-
return doBindText(property.getter, property.setter)
232-
}
233-
234-
private fun Cell<JBTextField>.doBindText(getter: () -> String, setter: (String) -> Unit): Cell<JBTextField> {
235-
component.text = getter()
236-
component.document.addDocumentListener(object : DocumentAdapter() {
237-
override fun textChanged(e: DocumentEvent) {
238-
setter(component.text)
239-
}
240-
})
241-
return this
242-
}
243-
244-
private fun <T> Cell<ComboBox<T>>.doBindItem(property: KMutableProperty0<T>): Cell<ComboBox<T>> {
245-
component.selectedItem = property.get()
246-
component.addActionListener {
247-
@Suppress("UNCHECKED_CAST")
248-
val selectedItem = component.selectedItem as T?
249-
if (selectedItem != null) {
250-
property.set(selectedItem)
251-
}
252-
}
253-
return this
254-
}
255-
256-
private fun Cell<JBTextField>.regexValidator(): Cell<JBTextField> {
257-
var hasRegisteredValidator = false
258-
component.onShown {
259-
if (!hasRegisteredValidator) {
260-
hasRegisteredValidator = true
261-
val disposable = DialogWrapper.findInstance(component)?.disposable ?: return@onShown
262-
ComponentValidator(disposable).withValidator(
263-
Supplier {
264-
try {
265-
Pattern.compile(component.text)
266-
null
267-
} catch (e: PatternSyntaxException) {
268-
ValidationInfoBuilder(component).error("Invalid regex")
269-
}
270-
}
271-
).andRegisterOnDocumentListener(component).installOn(component)
272-
}
273-
}
274-
return this
275-
}
276-
277-
private class RegexConverter : Converter<Regex>() {
278-
override fun toString(value: Regex) = value.pattern
279-
280-
override fun fromString(value: String) = runCatching { value.toRegex() }.getOrNull()
281-
}
282-
283213
private class RenameWithInheritanceFix(
284214
element: PsiNamedElement,
285215
private val newName: String

0 commit comments

Comments
 (0)