Desenvolvimento Android: Corrigindo o erro “line out of range” do SonarQube em projetos usando Jetpack Compose

André Theilacker
3 min readJan 15, 2024

--

Photo by Bermix Studio on Unsplash

Um problema que encontrei ao desenvolver projetos usando Jetpack Compose é gerar relatórios de cobertura de código que demonstrem corretamente a cobertura nas composable functions. Na maioria dos projetos, eu uso o JaCoCo para gerar os relatórios, que são enviados ao SonarQube para análise de métricas.

Mas o JaCoCo ainda não consegue demonstrar corretamente a cobertura nas funções marcadas com @Composable, e acaba reportando múltiplas linhas e caminhos invisíveis como não cobertos, já que o Compose gera várias linhas de bytecode que não são filtradas pelo JaCoCo, diferente do que acontece em casos como os syntactic sugars do Kotlin.

Em um projeto que trabalhei alguns meses atrás, notei um problema ainda pior: alguns arquivos estavam chegando a mostrar 0% de cobertura. Após investigar um pouco, identifiquei que o erro acontecia em arquivos com composable functions que chamavam métodos como o LaunchedEffect e alguns outros.

O relatório do JaCoCo estava sendo gerado sem problemas, mas ao tentar analisá-lo com o SonarQube o seguinte erro surgia:

[...]
Importing 1 report(s). Turn your logs in debug mode in order to see the exhaustive list.
Cannot import coverage information for file 'path/HelloWorld.kt', coverage data is invalid. Error: {}
java.lang.IllegalStateException: Line 65535 is out of range in the file path/HelloWorld.kt
[...]

O problema é que o relatório gerado pelo JaCoCo aponta para uma linha 65535 que não existe, o que faz com que o plugin do Sonar falhe. Após analisar o bug, parece que o problema está de fato no compilador do Jetpack Compose, que gera essa linha fantasma; apesar do JaCoCo incluir ela sem problemas no relatório, o problema explode na hora que chega ao Sonar.

No próprio issue tracker da Google já tem uma issue aberta para esse bug, mas ela não parece estar sendo priorizada. De qualquer forma, tem um fix temporário que pode ser aplicado nos projetos para resolver o erro; basta adicionar o trecho a seguir na hora de configurar sua task do JaCoCo:

Para scripts do Gradle que usem a DSL do Kotlin:

doLast {
val reportFile = reports.xml.outputLocation.asFile.get()
val newContent = reportFile.readText().replace("<line[^>]+nr=\"65535\"[^>]*>".toRegex(), "")
reportFile.writeText(newContent)
}

Para scripts do Gradle que usam Groovy:

doLast {
def reportFile = reports.xml.outputLocation.asFile.get()
def newContent = reportFile.text.replaceAll("<line[^>]+nr=\"65535\"[^>]*>", "")
reportFile.text = newContent
}

Se você faz essa configuração através de um convention plugin, o código precisará ser adaptado um pouco, mas ele deve funcionar da mesma forma. A ideia é remover a linha no relatório final que aponta para a linha inexistente, para que o plugin do Sonar consiga ler o arquivo sem quebrar.

Links para consulta:

Por hoje é só! Espero que esse artigo tenha sido útil. Se você tiver outras dicas para ajudar a melhorar a cobertura de código em projetos com Compose, sinta-se a vontade pra comentar!

A version written in English of this article is available here.

--

--