From 5cda15ff3cec99e90b99ea8bf26fb8b71cf87015 Mon Sep 17 00:00:00 2001 From: yairm210 Date: Tue, 29 Jul 2025 18:12:09 +0300 Subject: [PATCH] chore(purity): eliminate suppressions --- .../unciv/logic/civilization/Civilization.kt | 2 +- core/src/com/unciv/logic/map/mapunit/MapUnit.kt | 3 ++- .../unciv/models/ruleset/unique/Countables.kt | 6 +++--- .../unciv/models/translations/Translations.kt | 17 +++++++++-------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/core/src/com/unciv/logic/civilization/Civilization.kt b/core/src/com/unciv/logic/civilization/Civilization.kt index d930efdd92..acd5747f58 100644 --- a/core/src/com/unciv/logic/civilization/Civilization.kt +++ b/core/src/com/unciv/logic/civilization/Civilization.kt @@ -473,7 +473,7 @@ class Civilization : IsPartOfGameInfoSerialization { * Returns a dictionary of ALL resource names, and the amount that the civ has of each * Stockpiled resources return the stockpiled amount */ - @Readonly @Suppress("purity") // component1, component2 + @Readonly fun getCivResourcesByName(): HashMap { @LocalState val hashMap = HashMap(gameInfo.ruleset.tileResources.size) diff --git a/core/src/com/unciv/logic/map/mapunit/MapUnit.kt b/core/src/com/unciv/logic/map/mapunit/MapUnit.kt index ece8a5682d..dd9fc347bf 100644 --- a/core/src/com/unciv/logic/map/mapunit/MapUnit.kt +++ b/core/src/com/unciv/logic/map/mapunit/MapUnit.kt @@ -26,6 +26,7 @@ import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.UnitType import com.unciv.models.translations.tr import com.unciv.ui.components.UnitMovementMemoryType +import yairm210.purity.annotations.Cache import yairm210.purity.annotations.LocalState import yairm210.purity.annotations.Readonly import java.text.DecimalFormat @@ -67,7 +68,7 @@ class MapUnit : IsPartOfGameInfoSerialization { var automated: Boolean = false // We can infer who we are escorting based on our tile - var escorting: Boolean = false + @Cache private var escorting: Boolean = false var automatedRoadConnectionDestination: Vector2? = null // Temp disable, since this data broke saves diff --git a/core/src/com/unciv/models/ruleset/unique/Countables.kt b/core/src/com/unciv/models/ruleset/unique/Countables.kt index 3f0e20a969..4b216f97ab 100644 --- a/core/src/com/unciv/models/ruleset/unique/Countables.kt +++ b/core/src/com/unciv/models/ruleset/unique/Countables.kt @@ -258,7 +258,7 @@ enum class Countables( open val noPlaceholders = !text.contains('[') // Leave these in place only for the really simple cases - open fun matches(parameterText: String) = if (noPlaceholders) parameterText == text + @Readonly open fun matches(parameterText: String) = if (noPlaceholders) parameterText == text else parameterText.equalsPlaceholderText(placeholderText) /** Needs to return the ENTIRE countable, not just parameters. */ @@ -267,7 +267,7 @@ enum class Countables( /** This indicates whether a parameter *is of this countable type*, not *whether its parameters are correct* * E.g. "[fakeBuilding] Buildings" is obviously a countable of type "[buildingFilter] Buildings", therefore matches will return true. * But it has another problem, which is that the building filter is bad, so its getErrorSeverity will return "ruleset specific" */ - open fun matches(parameterText: String, ruleset: Ruleset): Boolean = false + @Readonly open fun matches(parameterText: String, ruleset: Ruleset): Boolean = false @Readonly @Suppress("purity") abstract fun eval(parameterText: String, gameContext: GameContext): Int? open val documentationHeader get() = @@ -290,7 +290,7 @@ enum class Countables( getErrorSeverity(parameterText.getPlaceholderParameters().first(), ruleset) companion object { - @Readonly @Suppress("purity") + @Readonly fun getMatching(parameterText: String, ruleset: Ruleset?) = Countables.entries .firstOrNull { if (it.matchesWithRuleset) diff --git a/core/src/com/unciv/models/translations/Translations.kt b/core/src/com/unciv/models/translations/Translations.kt index cadb326d0f..3bf51e9ef5 100644 --- a/core/src/com/unciv/models/translations/Translations.kt +++ b/core/src/com/unciv/models/translations/Translations.kt @@ -476,17 +476,17 @@ private fun String.translateIndividualWord(language: String, hideIcons: Boolean, * For example, a string like 'The city of [New [York]]' will return ['New [York]'], * allowing us to have nested translations! */ -@Readonly +@Pure @Suppress("purity") // IntRange.forEach should be recognized as pure fun String.getPlaceholderParameters(): List { if (!this.contains('[')) return emptyList() val stringToParse = this.removeConditionals() - @LocalState - val parameters = ArrayList() + @LocalState val parameters = ArrayList() var depthOfBraces = 0 var startOfCurrentParameter = -1 - for (i in stringToParse.indices) { + val stringIndices = stringToParse.indices + stringIndices.forEach { i -> if (stringToParse[i] == '[') { if (depthOfBraces == 0) startOfCurrentParameter = i+1 depthOfBraces++ @@ -499,16 +499,17 @@ fun String.getPlaceholderParameters(): List { return parameters } -@Readonly +@Pure fun String.getPlaceholderText(): String { var stringToReturn = this.removeConditionals() - val placeholderParameters = stringToReturn.getPlaceholderParameters() - for (placeholderParameter in placeholderParameters) + @LocalState val placeholderParameters = stringToReturn.getPlaceholderParameters() + placeholderParameters.forEach { placeholderParameter -> stringToReturn = stringToReturn.replaceFirst("[$placeholderParameter]", "[]") + } return stringToReturn } -@Readonly +@Pure fun String.equalsPlaceholderText(str: String): Boolean { if (isEmpty()) return str.isEmpty() if (str.isEmpty()) return false // Empty strings have no .first()