|
package io.freetrade.lintrules |
|
|
|
import com.android.tools.lint.client.api.UElementHandler |
|
import com.android.tools.lint.detector.api.Category |
|
import com.android.tools.lint.detector.api.Detector |
|
import com.android.tools.lint.detector.api.Implementation |
|
import com.android.tools.lint.detector.api.Issue |
|
import com.android.tools.lint.detector.api.JavaContext |
|
import com.android.tools.lint.detector.api.LintFix |
|
import com.android.tools.lint.detector.api.Scope |
|
import com.android.tools.lint.detector.api.Severity |
|
import org.jetbrains.uast.UCallExpression |
|
import org.jetbrains.uast.UElement |
|
|
|
class LokaliseStyledAttributeLintRule : Detector(), Detector.UastScanner { |
|
|
|
override fun getApplicableUastTypes(): List<Class<out UElement>>? { |
|
return listOf(UCallExpression::class.java) |
|
} |
|
|
|
override fun createUastHandler(context: JavaContext): UElementHandler? = Finder(context) |
|
|
|
companion object { |
|
|
|
val LOKALISE_STYLED_ATTRIBUTE = Issue.create( |
|
"StringFromAttributes", |
|
"Strings from attributes can't be replaced at runtime", |
|
"Lokalise won't replace strings retrieved by attributes. Fetch the resource ID from the attributes and use resources.getString() on that.", |
|
Category.I18N, |
|
8, |
|
Severity.ERROR, |
|
Implementation(LokaliseStyledAttributeLintRule::class.java, Scope.JAVA_FILE_SCOPE) |
|
) |
|
} |
|
} |
|
|
|
private class Finder(private val context: JavaContext) : UElementHandler() { |
|
|
|
override fun visitCallExpression(node: UCallExpression) { |
|
if (node.isCallWeShouldWarnOf()) { |
|
val attributeArgument = node.firstArgumentName() |
|
context.report( |
|
LokaliseStyledAttributeLintRule.LOKALISE_STYLED_ATTRIBUTE, |
|
context.getLocation(node), |
|
"String from attribute $attributeArgument is not replaceable by Localize.", |
|
fixFor(node) |
|
) |
|
} |
|
} |
|
|
|
private fun UCallExpression.firstArgumentName() = valueArguments.firstOrNull()?.asRenderString() |
|
|
|
// Warn for TypedArray.getString(int) |
|
private fun UCallExpression.isCallWeShouldWarnOf(): Boolean { |
|
val receiverClass = receiverType?.getCanonicalText(false) ?: "" |
|
return receiverClass.contains("TypedArray") && methodName == "getString" |
|
} |
|
|
|
private fun fixFor(node: UCallExpression): LintFix = LintFix.create() |
|
.name("Fetch via Resources instead") |
|
.replace() |
|
.autoFix() |
|
.reformat(true) |
|
.shortenNames() |
|
.with("${node.receiver?.asRenderString()}.getStringFromResources(resources, ${node.firstArgumentName()})") |
|
.build() |
|
} |