Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Static Analysis - Kotlin Everywhere 2019

Kotlin Static Analysis - Kotlin Everywhere 2019

Slides for my Kotlin Everywhere talk.

Matheus Cassiano Candido

October 05, 2019
Tweet

More Decks by Matheus Cassiano Candido

Other Decks in Programming

Transcript

  1. Mantendo código Kotlin seguro: de ponta a ponta Matheus C.

    Candido Mobile Software Engineer @ Uber
  2. Análise estática Static program analysis is the analysis of computer

    software that is performed without actually executing programs
  3. Ktlint Simples, drop-in Zero configuração Code styling* Formatador Baseado no

    Kotlin Style Guide, mas suporta Android Style Guide
  4. Android Lint Java, Kotlin e Resources Regras especiais para Android

    Super extensível Performance Análise de recursos duplicados/não utilizados
  5. Android Lint Java, Kotlin e Resources Regras especiais para Android

    Super extensível Performance Análise de recursos duplicados/não utilizados Funciona para projetos não-Android
  6. Issue registry @AutoService(IssueRegistry::class) class Registry() :fIssueRegistry() {f override val issues:

    List<Issue> = listOf(GetDrawableDetector.ISSUE) override val api: Int = CURRENT_API }f
  7. Issue registry @AutoService(IssueRegistry::class) class Registry() :fIssueRegistry() {f override val issues:

    List<Issue> = listOf(GetDrawableDetector.ISSUE) override val api: Int = CURRENT_API }f
  8. Issue registry @AutoService(IssueRegistry::class) class Registry() :fIssueRegistry() {f override val issues:

    List<Issue> = listOf(GetDrawableDetector.ISSUE) override val api: Int = CURRENT_API }f
  9. Criando um detector /** *fDetector to check for usages of

    `ResourcesCompat.getDrawable` or `ContextCompat.getDrawable`. */ class GetDrawableDetector :fDetector(), SourceCodeScanner {f companion object {f val ISSUE =fIssue.create(f id =fISSUE_ID, briefDescription =fBRIEF_DESCRIPTION, explanation =fLINT_ERROR_MESSAGE, category =fCategory.CORRECTNESS,
  10. Descrição da Issue val ISSUE =fIssue.create(f id =fISSUE_ID, briefDescription =fBRIEF_DESCRIPTION,

    explanation =fLINT_ERROR_MESSAGE, category =fCategory.CORRECTNESS, priority =f6, severity =fSeverity.ERROR, implementation =fcreate<GetDrawableDetector>()) }f override fun getApplicableMethodNames() = listOf("getDrawable") override fun visitMethodCall(f context:fJavaContext,
  11. Descrição da Issue val ISSUE =fIssue.create(f id =fISSUE_ID, briefDescription =fBRIEF_DESCRIPTION,

    explanation =fLINT_ERROR_MESSAGE, category =fCategory.CORRECTNESS, priority =f6, severity =fSeverity.ERROR, implementation =fcreate<GetDrawableDetector>()) }f override fun getApplicableMethodNames() = listOf("getDrawable") override fun visitMethodCall(f context:fJavaContext,
  12. Descrição da Issue val ISSUE =fIssue.create(f id =fISSUE_ID, briefDescription =fBRIEF_DESCRIPTION,

    explanation =fLINT_ERROR_MESSAGE, category =fCategory.CORRECTNESS, priority =f6, severity =fSeverity.ERROR, implementation =fcreate<GetDrawableDetector>()) }f override fun getApplicableMethodNames() = listOf("getDrawable") override fun visitMethodCall(f context:fJavaContext,
  13. Descrição da Issue val ISSUE =fIssue.create(f id =fISSUE_ID, briefDescription =fBRIEF_DESCRIPTION,

    explanation =fLINT_ERROR_MESSAGE, category =fCategory.CORRECTNESS, priority =f6, severity =fSeverity.ERROR, implementation =fcreate<GetDrawableDetector>()) }f override fun getApplicableMethodNames() =f listOf("getDrawable") override fun visitMethodCall(f context:fJavaContext,
  14. Filtrando a entrada overrideffunfgetApplicableMethodNames() =f listOf("getDrawable")f override fun visitMethodCall(f context:fJavaContext,

    node:fUCallExpression, method:fPsiMethod ){f iff(! getApplicableMethodNames().contains(node.methodName))freturn if (node.methodName == "getDrawable" && isBlacklisted(context.evaluator, node)) {f context.report(ISSUE, context.getLocation(node),
  15. Detectando os problemas override fun visitMethodCall(f context:fJavaContext, node:fUCallExpression, method:fPsiMethod ){f

    iff(! getApplicableMethodNames().contains(node.methodName))freturn if (node.methodName == "getDrawable" && isBlacklisted(context.evaluator, node)) {f context.report(ISSUE, context.getLocation(node), LINT_ERROR_MESSAGE) }f
  16. Detectando os problemas iff(! getApplicableMethodNames().contains(node.methodName))freturn if (node.methodName == "getDrawable" &&

    isBlacklisted(context.evaluator, node)) {f context.report(ISSUE, context.getLocation(node), LINT_ERROR_MESSAGE) }f }f private fun isBlacklisted():fBoolean {f return evaluator.isMemberInClass(node.resolve(), "androidx.core.content.ContextCompat") ||f
  17. Detectando os problemas iff(! getApplicableMethodNames().contains(node.methodName))freturn if (node.methodName == "getDrawable" &&

    isBlacklisted(context.evaluator, node)) {f context.report(ISSUE, context.getLocation(node), LINT_ERROR_MESSAGE) }f }f private fun isBlacklisted():fBoolean {f return evaluator.isMemberInClass(node.resolve(), "androidx.core.content.ContextCompat") ||f
  18. Detectando os problemas context.report(ISSUE, context.getLocation(node), LINT_ERROR_MESSAGE) }f }f private fun

    isBlacklisted():fBoolean {f return evaluator.isMemberInClass(node.resolve(),f "androidx.core.content.ContextCompat") ||f evaluator.isMemberInClass(node.resolve(), "androidx.core.content.res.ResourcesCompat")f }f }f
  19. Usando a nova regra // no build.gradle dos outros projetos

    dependencies {f lintChecks project(":meu_detector") }f
  20. Usando a nova regra // no build.gradle dos outros projetos

    dependencies {f lintChecks project(":meu_detector") }f
  21. Resumo Combine as ferramentas e aproveite o melhor de cada

    uma Aplique as regras que façam sentido para seu contexto
  22. Resumo Combine as ferramentas e aproveite o melhor de cada

    uma Aplique as regras que façam sentido para seu contexto Automatize a formatação dos arquivos e partes do code review