diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/internal/util/LogcatLogger.kt b/checkout-core/src/main/java/com/adyen/checkout/core/internal/util/LogcatLogger.kt index 4f72379412..1cbd5eec2d 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/internal/util/LogcatLogger.kt +++ b/checkout-core/src/main/java/com/adyen/checkout/core/internal/util/LogcatLogger.kt @@ -8,6 +8,7 @@ package com.adyen.checkout.core.internal.util +import android.annotation.SuppressLint import android.os.Build import android.util.Log import com.adyen.checkout.core.AdyenLogLevel @@ -59,6 +60,7 @@ internal class LogcatLogger : AdyenLogger { } } + @SuppressLint("NotAdyenLog") private fun logToLogcat( priority: Int, tag: String, diff --git a/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt b/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt index 67f929828f..7c242532c5 100644 --- a/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt +++ b/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt @@ -18,6 +18,7 @@ internal class LintIssueRegistry : IssueRegistry() { override val api: Int = CURRENT_API override val issues: List = listOf( + NOT_ADYEN_LOG_ISSUE, OBJECT_IN_PUBLIC_SEALED_CLASS_ISSUE, ) } diff --git a/lint/src/main/java/com/adyen/checkout/lint/NotAdyenLog.kt b/lint/src/main/java/com/adyen/checkout/lint/NotAdyenLog.kt new file mode 100644 index 0000000000..371d2bd109 --- /dev/null +++ b/lint/src/main/java/com/adyen/checkout/lint/NotAdyenLog.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by oscars on 14/8/2024. + */ + +package com.adyen.checkout.lint + +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.Scope +import com.android.tools.lint.detector.api.Severity +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.UCallExpression + +internal val NOT_ADYEN_LOG_ISSUE = Issue.create( + id = "NotAdyenLog", + briefDescription = "Log used instead of adyenLog", + explanation = "adyenLog should be used, so we have control over the logs.", + implementation = Implementation(NotAdyenLogDetector::class.java, Scope.JAVA_FILE_SCOPE), + category = Category.MESSAGES, + priority = 5, + severity = Severity.ERROR, +) + +internal class NotAdyenLogDetector : Detector(), Detector.UastScanner { + + override fun getApplicableMethodNames(): List = listOf( + "v", "d", "i", "w", "e", "wtf", + ) + + override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { + if (context.evaluator.isMemberInClass(method, "android.util.Log")) { + context.report( + NOT_ADYEN_LOG_ISSUE, + node, + context.getLocation(node), + "Log used instead of adyenLog", + ) + } + } +} diff --git a/lint/src/test/java/com/adyen/checkout/lint/NotAdyenLogTest.kt b/lint/src/test/java/com/adyen/checkout/lint/NotAdyenLogTest.kt new file mode 100644 index 0000000000..9f5489feee --- /dev/null +++ b/lint/src/test/java/com/adyen/checkout/lint/NotAdyenLogTest.kt @@ -0,0 +1,76 @@ +package com.adyen.checkout.lint + +import com.android.tools.lint.checks.infrastructure.LintDetectorTest.kotlin +import com.android.tools.lint.checks.infrastructure.TestLintTask.lint +import org.junit.Test + +internal class NotAdyenLogTest { + + @Test + fun whenAndroidLogIsUsed_thenIssueIsDetected() { + lint() + .files( + ANDROID_LOG_STUB, + kotlin( + """ + package test + + import android.util.Log + + fun androidLog() { + Log.v("tag", "message") + Log.d("tag", "message") + Log.i("tag", "message") + Log.w("tag", "message") + Log.e("tag", "message") + Log.wtf("tag", "message") + } + """, + ).indented(), + ) + .issues(NOT_ADYEN_LOG_ISSUE) + .allowMissingSdk() + .run() + .expect( + """ + src/test/test.kt:6: Error: Log used instead of adyenLog [NotAdyenLog] + Log.v("tag", "message") + ~~~~~~~~~~~~~~~~~~~~~~~ + src/test/test.kt:7: Error: Log used instead of adyenLog [NotAdyenLog] + Log.d("tag", "message") + ~~~~~~~~~~~~~~~~~~~~~~~ + src/test/test.kt:8: Error: Log used instead of adyenLog [NotAdyenLog] + Log.i("tag", "message") + ~~~~~~~~~~~~~~~~~~~~~~~ + src/test/test.kt:9: Error: Log used instead of adyenLog [NotAdyenLog] + Log.w("tag", "message") + ~~~~~~~~~~~~~~~~~~~~~~~ + src/test/test.kt:10: Error: Log used instead of adyenLog [NotAdyenLog] + Log.e("tag", "message") + ~~~~~~~~~~~~~~~~~~~~~~~ + src/test/test.kt:11: Error: Log used instead of adyenLog [NotAdyenLog] + Log.wtf("tag", "message") + ~~~~~~~~~~~~~~~~~~~~~~~~~ + 6 errors, 0 warnings + """ + ) + } + + companion object { + + private val ANDROID_LOG_STUB = kotlin( + """ + package android.util + + object Log { + fun v(tag: String, msg: String, tr: Throwable? = null) {} + fun d(tag: String, msg: String, tr: Throwable? = null) {} + fun i(tag: String, msg: String, tr: Throwable? = null) {} + fun w(tag: String, msg: String, tr: Throwable? = null) {} + fun e(tag: String, msg: String, tr: Throwable? = null) {} + fun wtf(tag: String, msg: String, tr: Throwable? = null) {} + } + """, + ).indented() + } +}