aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCalMWolfs <94038482+CalMWolfs@users.noreply.github.com>2024-10-20 16:22:32 +1100
committerGitHub <noreply@github.com>2024-10-20 16:22:32 +1100
commit5336712212c555f6e8d0f72c94cb7dd8d7504f11 (patch)
tree86c715a7c3e63b3bdf89033e746a9dd808de56aa
parentb4623d5c67ac3e1a006bafd3de59f518e3433bd7 (diff)
downloadSkyHanni-5336712212c555f6e8d0f72c94cb7dd8d7504f11.tar.gz
SkyHanni-5336712212c555f6e8d0f72c94cb7dd8d7504f11.tar.bz2
SkyHanni-5336712212c555f6e8d0f72c94cb7dd8d7504f11.zip
Backend: Add custom import ordering detekt rule (#2775)
-rw-r--r--detekt/baseline.xml2
-rw-r--r--detekt/detekt.yml7
-rw-r--r--detekt/src/main/kotlin/PreprocessingPatterns.kt19
-rw-r--r--detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt12
-rw-r--r--detekt/src/main/kotlin/imports/CustomImportOrdering.kt114
-rw-r--r--detekt/src/main/kotlin/imports/ImportRuleSetProvider.kt17
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt11
-rw-r--r--versions/1.8.9/detekt/baseline.xml2
10 files changed, 171 insertions, 18 deletions
diff --git a/detekt/baseline.xml b/detekt/baseline.xml
index c9151e8ae..338c7d66d 100644
--- a/detekt/baseline.xml
+++ b/detekt/baseline.xml
@@ -30,8 +30,6 @@
<ID>CyclomaticComplexMethod:VampireSlayerFeatures.kt$VampireSlayerFeatures$private fun EntityOtherPlayerMP.process()</ID>
<ID>CyclomaticComplexMethod:VisualWordGui.kt$VisualWordGui$override fun drawScreen(unusedX: Int, unusedY: Int, partialTicks: Float)</ID>
<ID>Filename:AreaChangeEvents.kt$at.hannibal2.skyhanni.events.skyblock.AreaChangeEvents.kt</ID>
- <ID>ImportOrdering:DungeonLividFinder.kt$import at.hannibal2.skyhanni.events.CheckRenderEntityEvent import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.BlockUtils.getBlockStateAt import at.hannibal2.skyhanni.utils.ColorUtils.withAlpha import at.hannibal2.skyhanni.utils.EntityUtils import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzColor.Companion.toLorenzColor import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText import at.hannibal2.skyhanni.utils.RenderUtils.drawLineToEye import at.hannibal2.skyhanni.utils.RenderUtils.drawWaypointFilled import at.hannibal2.skyhanni.utils.RenderUtils.exactLocation import net.minecraft.block.BlockStainedGlass import net.minecraft.client.entity.EntityOtherPlayerMP import net.minecraft.client.entity.EntityPlayerSP import net.minecraft.client.Minecraft import net.minecraft.entity.item.EntityArmorStand import net.minecraft.potion.Potion import net.minecraft.util.AxisAlignedBB import net.minecraftforge.fml.common.eventhandler.SubscribeEvent</ID>
- <ID>ImportOrdering:EntityUtils.kt$import at.hannibal2.skyhanni.data.mob.MobFilter.isRealPlayer import at.hannibal2.skyhanni.events.SkyHanniRenderEntityEvent import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ItemUtils.getSkullTexture import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen import at.hannibal2.skyhanni.utils.LocationUtils.distanceTo import at.hannibal2.skyhanni.utils.LocationUtils.distanceToIgnoreY import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth import at.hannibal2.skyhanni.utils.LorenzUtils.derpy import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.compat.getArmorOrFullInventory import at.hannibal2.skyhanni.utils.compat.getLoadedPlayers import at.hannibal2.skyhanni.utils.compat.getNameAsString import at.hannibal2.skyhanni.utils.compat.isOnMainThread import at.hannibal2.skyhanni.utils.compat.normalizeAsArray import net.minecraft.block.state.IBlockState import net.minecraft.client.Minecraft import net.minecraft.client.entity.EntityOtherPlayerMP import net.minecraft.client.multiplayer.WorldClient import net.minecraft.entity.Entity import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.item.EntityArmorStand import net.minecraft.entity.monster.EntityEnderman import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.potion.Potion import net.minecraft.tileentity.TileEntity import net.minecraft.util.AxisAlignedBB import net.minecraftforge.client.event.RenderLivingEvent //#if FORGE import net.minecraftforge.fml.common.eventhandler.Event import net.minecraftforge.fml.common.eventhandler.SubscribeEvent</ID>
<ID>InjectDispatcher:ClipboardUtils.kt$ClipboardUtils$IO</ID>
<ID>InjectDispatcher:GardenNextJacobContest.kt$GardenNextJacobContest$IO</ID>
<ID>InjectDispatcher:HypixelBazaarFetcher.kt$HypixelBazaarFetcher$IO</ID>
diff --git a/detekt/detekt.yml b/detekt/detekt.yml
index ac5c9de53..014ca8c5a 100644
--- a/detekt/detekt.yml
+++ b/detekt/detekt.yml
@@ -12,6 +12,11 @@ FormattingRules:
CustomCommentSpacing:
active: true
+ImportRules:
+ active: true
+ CustomImportOrdering:
+ active: true
+
style:
MagicNumber: # I, Linnea Gräf, of sound mind and body, disagree with disabling this rule
@@ -73,6 +78,8 @@ formatting:
active: false
SpacingBetweenDeclarationsWithComments: # also nah
active: false
+ ImportOrdering: # handled by custom rule
+ active: false
complexity:
CyclomaticComplexMethod: # default threshold of 15, caught almost every complex method
diff --git a/detekt/src/main/kotlin/PreprocessingPatterns.kt b/detekt/src/main/kotlin/PreprocessingPatterns.kt
new file mode 100644
index 000000000..695f088cf
--- /dev/null
+++ b/detekt/src/main/kotlin/PreprocessingPatterns.kt
@@ -0,0 +1,19 @@
+package at.hannibal2.skyhanni.detektrules
+
+enum class PreprocessingPattern(val text: String) {
+ IF("#if"),
+ ELSE("#else"),
+ ELSEIF("#elseif"),
+ ENDIF("#endif"),
+ DOLLAR_DOLLAR("$$"),
+ ;
+
+ val asComment: String
+ get() = "//$text"
+
+ companion object {
+ fun String.containsPreprocessingPattern(): Boolean {
+ return entries.any { this.contains(it.text) }
+ }
+ }
+}
diff --git a/detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt b/detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt
index aaf7896cf..db9f2f8a7 100644
--- a/detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt
+++ b/detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt
@@ -1,5 +1,6 @@
package at.hannibal2.skyhanni.detektrules.formatting
+import at.hannibal2.skyhanni.detektrules.PreprocessingPattern.Companion.containsPreprocessingPattern
import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.Debt
@@ -17,18 +18,9 @@ class CustomCommentSpacing(config: Config) : Rule(config) {
Debt.FIVE_MINS
)
- private val allowedPatterns = listOf(
- "#if",
- "#else",
- "#elseif",
- "#endif",
- "$$"
- )
override fun visitComment(comment: PsiComment) {
- if (allowedPatterns.any { comment.text.contains(it) }) {
- return
- }
+ if (comment.text.containsPreprocessingPattern()) return
/**
* REGEX-TEST: // Test comment
diff --git a/detekt/src/main/kotlin/imports/CustomImportOrdering.kt b/detekt/src/main/kotlin/imports/CustomImportOrdering.kt
new file mode 100644
index 000000000..9e0302153
--- /dev/null
+++ b/detekt/src/main/kotlin/imports/CustomImportOrdering.kt
@@ -0,0 +1,114 @@
+package at.hannibal2.skyhanni.detektrules.imports
+
+import at.hannibal2.skyhanni.detektrules.PreprocessingPattern
+import at.hannibal2.skyhanni.detektrules.PreprocessingPattern.Companion.containsPreprocessingPattern
+import io.gitlab.arturbosch.detekt.api.CodeSmell
+import io.gitlab.arturbosch.detekt.api.Config
+import io.gitlab.arturbosch.detekt.api.Debt
+import io.gitlab.arturbosch.detekt.api.Entity
+import io.gitlab.arturbosch.detekt.api.Issue
+import io.gitlab.arturbosch.detekt.api.Rule
+import io.gitlab.arturbosch.detekt.api.Severity
+import org.jetbrains.kotlin.psi.KtImportDirective
+import org.jetbrains.kotlin.psi.KtImportList
+
+class CustomImportOrdering(config: Config) : Rule(config) {
+ override val issue = Issue(
+ "CustomImportOrdering",
+ Severity.Style,
+ "Enforces correct import ordering, taking into account preprocessed imports.",
+ Debt.FIVE_MINS,
+ )
+
+ companion object {
+ private val importOrder = ImportSorter()
+
+ private val packageImportOrdering = listOf("java.", "javax.", "kotlin.")
+
+ private class ImportSorter : Comparator<KtImportDirective> {
+ override fun compare(
+ import1: KtImportDirective,
+ import2: KtImportDirective,
+ ): Int {
+ val importPath1 = import1.importPath!!.pathStr
+ val importPath2 = import2.importPath!!.pathStr
+
+ val isTypeAlias1 = import1.aliasName != null
+ val isTypeAlias2 = import2.aliasName != null
+
+ val index1 = packageImportOrdering.indexOfFirst { importPath1.startsWith(it) }
+ val index2 = packageImportOrdering.indexOfFirst { importPath2.startsWith(it) }
+
+ return when {
+ isTypeAlias1 && isTypeAlias2 -> importPath1.compareTo(importPath2)
+ isTypeAlias1 && !isTypeAlias2 -> 1
+ !isTypeAlias1 && isTypeAlias2 -> -1
+ index1 == -1 && index2 == -1 -> importPath1.compareTo(importPath2)
+ index1 == -1 -> -1
+ index2 == -1 -> 1
+ else -> index1.compareTo(index2)
+ }
+ }
+ }
+ }
+
+ private fun isImportsCorrectlyOrdered(imports: List<KtImportDirective>, rawText: List<String>): Boolean {
+ if (rawText.any { it.isBlank() }) {
+ return false
+ }
+
+ var inPreprocess = false
+ val linesToIgnore = mutableListOf<String>()
+
+ for (line in rawText) {
+ if (line.contains(PreprocessingPattern.IF.asComment)) {
+ inPreprocess = true
+ continue
+ }
+ if (line.contains(PreprocessingPattern.ENDIF.asComment)) {
+ inPreprocess = false
+ continue
+ }
+ if (line.contains(PreprocessingPattern.DOLLAR_DOLLAR.asComment)) {
+ continue
+ }
+ if (inPreprocess) {
+ linesToIgnore.add(line)
+ }
+ }
+
+ val originalImports = rawText.filter { !it.containsPreprocessingPattern() && !linesToIgnore.contains(it) }
+ val formattedOriginal = originalImports.joinToString("\n") { it }
+
+ val expectedImports = imports.sortedWith(importOrder).map { "import ${it.importPath}" }
+ val formattedExpected = expectedImports.filter { !linesToIgnore.contains(it) }.joinToString("\n")
+
+ return formattedOriginal == formattedExpected
+ }
+
+ override fun visitImportList(importList: KtImportList) {
+
+ val testEntity = Entity.from(importList)
+
+ val rawText = importList.text.trim()
+ if (rawText.isBlank()) {
+ return
+ }
+
+ val importsCorrect = isImportsCorrectlyOrdered(importList.imports, rawText.lines())
+
+ if (!importsCorrect) {
+ report(
+ CodeSmell(
+ issue,
+ testEntity,
+ "Imports must be ordered in lexicographic order without any empty lines in-between " +
+ "with \"java\", \"javax\", \"kotlin\" and aliases in the end. This should then be followed by " +
+ "pre-processed imports.",
+ ),
+ )
+ }
+
+ super.visitImportList(importList)
+ }
+}
diff --git a/detekt/src/main/kotlin/imports/ImportRuleSetProvider.kt b/detekt/src/main/kotlin/imports/ImportRuleSetProvider.kt
new file mode 100644
index 000000000..3b50cf22c
--- /dev/null
+++ b/detekt/src/main/kotlin/imports/ImportRuleSetProvider.kt
@@ -0,0 +1,17 @@
+package at.hannibal2.skyhanni.detektrules.imports
+
+import com.google.auto.service.AutoService
+import io.gitlab.arturbosch.detekt.api.Config
+import io.gitlab.arturbosch.detekt.api.RuleSet
+import io.gitlab.arturbosch.detekt.api.RuleSetProvider
+
+@AutoService(RuleSetProvider::class)
+class ImportRuleSetProvider : RuleSetProvider {
+ override val ruleSetId: String = "ImportRules"
+
+ override fun instance(config: Config): RuleSet {
+ return RuleSet(ruleSetId, listOf(
+ CustomImportOrdering(config)
+ ))
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt
index 6049268c8..e934e0027 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt
@@ -1,11 +1,11 @@
package at.hannibal2.skyhanni.features.dungeon
+import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.events.CheckRenderEntityEvent
import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
import at.hannibal2.skyhanni.events.LorenzTickEvent
import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper
-import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.test.command.ErrorManager
import at.hannibal2.skyhanni.utils.BlockUtils.getBlockStateAt
@@ -20,9 +20,9 @@ import at.hannibal2.skyhanni.utils.RenderUtils.drawLineToEye
import at.hannibal2.skyhanni.utils.RenderUtils.drawWaypointFilled
import at.hannibal2.skyhanni.utils.RenderUtils.exactLocation
import net.minecraft.block.BlockStainedGlass
+import net.minecraft.client.Minecraft
import net.minecraft.client.entity.EntityOtherPlayerMP
import net.minecraft.client.entity.EntityPlayerSP
-import net.minecraft.client.Minecraft
import net.minecraft.entity.item.EntityArmorStand
import net.minecraft.potion.Potion
import net.minecraft.util.AxisAlignedBB
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt
index a49ceace8..15dc807bb 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt
@@ -36,7 +36,6 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
//#endif
@SkyHanniModule
-@Suppress("ImportOrdering")
object EntityUtils {
@Deprecated("Old. Instead use entity detection feature instead.")
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt b/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt
index e1dab5dca..d09d348b5 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt
@@ -19,11 +19,15 @@ import kotlinx.coroutines.launch
import net.minecraft.client.Minecraft
import net.minecraft.client.network.NetworkPlayerInfo
import net.minecraft.network.play.server.S38PacketPlayerListItem
-import net.minecraft.world.WorldSettings
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
import kotlin.time.Duration.Companion.seconds
+//#if MC<1.12
+import net.minecraft.world.WorldSettings
+//#else
+//$$ import net.minecraft.world.GameType
+//#endif
@SkyHanniModule
object TabListData {
@@ -92,8 +96,13 @@ object TabListData {
val team1 = o1.playerTeam
val team2 = o2.playerTeam
return ComparisonChain.start().compareTrueFirst(
+ //#if MC<1.12
o1.gameType != WorldSettings.GameType.SPECTATOR,
o2.gameType != WorldSettings.GameType.SPECTATOR
+ //#else
+ //$$ o1.gameType != GameType.SPECTATOR,
+ //$$ o2.gameType != GameType.SPECTATOR
+ //#endif
)
.compare(
if (team1 != null) team1.registeredName else "",
diff --git a/versions/1.8.9/detekt/baseline.xml b/versions/1.8.9/detekt/baseline.xml
index c9151e8ae..338c7d66d 100644
--- a/versions/1.8.9/detekt/baseline.xml
+++ b/versions/1.8.9/detekt/baseline.xml
@@ -30,8 +30,6 @@
<ID>CyclomaticComplexMethod:VampireSlayerFeatures.kt$VampireSlayerFeatures$private fun EntityOtherPlayerMP.process()</ID>
<ID>CyclomaticComplexMethod:VisualWordGui.kt$VisualWordGui$override fun drawScreen(unusedX: Int, unusedY: Int, partialTicks: Float)</ID>
<ID>Filename:AreaChangeEvents.kt$at.hannibal2.skyhanni.events.skyblock.AreaChangeEvents.kt</ID>
- <ID>ImportOrdering:DungeonLividFinder.kt$import at.hannibal2.skyhanni.events.CheckRenderEntityEvent import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.BlockUtils.getBlockStateAt import at.hannibal2.skyhanni.utils.ColorUtils.withAlpha import at.hannibal2.skyhanni.utils.EntityUtils import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzColor.Companion.toLorenzColor import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText import at.hannibal2.skyhanni.utils.RenderUtils.drawLineToEye import at.hannibal2.skyhanni.utils.RenderUtils.drawWaypointFilled import at.hannibal2.skyhanni.utils.RenderUtils.exactLocation import net.minecraft.block.BlockStainedGlass import net.minecraft.client.entity.EntityOtherPlayerMP import net.minecraft.client.entity.EntityPlayerSP import net.minecraft.client.Minecraft import net.minecraft.entity.item.EntityArmorStand import net.minecraft.potion.Potion import net.minecraft.util.AxisAlignedBB import net.minecraftforge.fml.common.eventhandler.SubscribeEvent</ID>
- <ID>ImportOrdering:EntityUtils.kt$import at.hannibal2.skyhanni.data.mob.MobFilter.isRealPlayer import at.hannibal2.skyhanni.events.SkyHanniRenderEntityEvent import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ItemUtils.getSkullTexture import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen import at.hannibal2.skyhanni.utils.LocationUtils.distanceTo import at.hannibal2.skyhanni.utils.LocationUtils.distanceToIgnoreY import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth import at.hannibal2.skyhanni.utils.LorenzUtils.derpy import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.compat.getArmorOrFullInventory import at.hannibal2.skyhanni.utils.compat.getLoadedPlayers import at.hannibal2.skyhanni.utils.compat.getNameAsString import at.hannibal2.skyhanni.utils.compat.isOnMainThread import at.hannibal2.skyhanni.utils.compat.normalizeAsArray import net.minecraft.block.state.IBlockState import net.minecraft.client.Minecraft import net.minecraft.client.entity.EntityOtherPlayerMP import net.minecraft.client.multiplayer.WorldClient import net.minecraft.entity.Entity import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.item.EntityArmorStand import net.minecraft.entity.monster.EntityEnderman import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.potion.Potion import net.minecraft.tileentity.TileEntity import net.minecraft.util.AxisAlignedBB import net.minecraftforge.client.event.RenderLivingEvent //#if FORGE import net.minecraftforge.fml.common.eventhandler.Event import net.minecraftforge.fml.common.eventhandler.SubscribeEvent</ID>
<ID>InjectDispatcher:ClipboardUtils.kt$ClipboardUtils$IO</ID>
<ID>InjectDispatcher:GardenNextJacobContest.kt$GardenNextJacobContest$IO</ID>
<ID>InjectDispatcher:HypixelBazaarFetcher.kt$HypixelBazaarFetcher$IO</ID>