Integrando Ferramentas de Análise de Código no Android — Parte III: PMD

Padrão

Olá pessoal! Dando continuidade a nossa série de posts, hoje vamos conhecer o matador de bugs, o PMD.

Apesar de parecer uma sigla, de fato, nem os criadores sabem o que PMD significa. Atualmente em sua versão 5.4.1, ele possui regras que denunciam desde try/catches vazios até código copiado.

Como o Gradle possui nativamente um plugin do PMD, sua integração é tão simples quanto as outras ferramentas que já vimos. Primeiramente, vamos aplicar o plugin no nosso arquivo build.gradle:

apply plugin: 'pmd'

Da mesma forma que fizemos com as outras ferramentas, uma recomendação é adicionarmos a task que vamos criar à task check:

check.dependsOn 'checkstyle', 'findbugs', 'pmd'

O próximo passo é criar a nossa task. Ela é muito semelhante àquela que criamos para o FindBugs, com a diferença de que as propriedades que utilizamos para configurar as regras de validação se chamam ruleSetsruleSetFiles. Da mesma forma que o FindBugs, com o PMD também temos a possibilidade de gerar o relatório tanto em formato XML quanto HTML.

A task completa fica assim:

task pmd(type: Pmd) {
    ignoreFailures = false
    ruleSetFiles = files("${project.rootDir}/config/pmd-ruleset.xml")
    ruleSets = []

    source 'src'
    include '**/*.java'
    exclude '**/gen/**'

    reports {
        xml.enabled = false
        html.enabled = true
        html {
            destination "$project.buildDir/reports/findbugs/findbugs.html"
        }
    }
}

O arquivo de configuração pmd-ruleset.xml contém as regras que serão aplicadas ao processo de validação dos nossos arquivos. Um exemplo:

<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Android Application Rules" xmlns="http://pmd.sf.net/ruleset/1.0.0" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd">

    <exclude-pattern>.*/R.java</exclude-pattern>
    <exclude-pattern>.*/gen/.*</exclude-pattern>

    <rule ref="rulesets/java/android.xml" />
</ruleset>

Todas as regras disponíveis para o PMD podem ser encontradas aqui. E como o próprio pessoal do PMD diz, nenhuma regra é escrita na pedra, é possível remover determinadas verificações de um ruleset. No contexto do Android, um caso onde isso é necessário é quando adicionamos a regra de Import Statements e estamos utilizando o Espresso, cujo design visa a fluência na leitura dos testes escritos. Esse design muitas vezes acaba gerando um grande número de imports estáticos, o que entra em conflito com a regra TooManyStaticImports do PMD. Caso haja a necessidade de remover alguma regra de um ruleset, podemos fazer isso no arquivo de configuração desta forma:

<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Android Application Rules" xmlns="http://pmd.sf.net/ruleset/1.0.0" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd">

    <exclude-pattern>.*/R.java</exclude-pattern>
    <exclude-pattern>.*/gen/.*</exclude-pattern>

    <rule ref="rulesets/java/android.xml" />
    <rule ref="rulesets/java/imports.xml">
        <exclude name="TooManyStaticImports" />
    </rule>
</ruleset>

Executando a task pmd em um terminal (ou utilizando o menu Gradle dentro do Android Studio), podemos ter uma análise de código baseada nas regras que configuramos.

Pegando como exemplo o ruleset android que adicionamos a nossa configuração, podemos simular o erro comum de utilizar a localização da memória externa hardcoded como /sdcard. Assim, temos como resultado o seguinte relatório:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ‘:app:pmd’.
> 1 PMD rule violations were found. See the report at: file:///Users/rafael/Project/quality-tools/app/build/reports/findbugs/findbugs.html

* Try:
Run with — stacktrace option to get the stack trace. Run with — info or — debug option to get more log output.

BUILD FAILED

O conteúdo do relatório é o seguinte:

1-aEobIoDE03qbUKvJPBnIOw

O link no relatório leva até a descrição detalhada do problema no próprio site do PMD.

E é isso, pessoal! Na próxima e última parte dessa série de posts, veremos como realizar um ajuste fino da execução do Lint para melhorar a qualidade do nosso aplicativo e evitar que problemas conhecidos e más práticas acabem afetando o desempenho em produção. Até lá!