Arquivos de filtro

Arquivos de filtro podem ser usados para incluir ou excluir o reporte de bugs para classes e métodos específicos. Este capítulo explica como usar os arquivos de filtro.

Introdução aos arquivos de filtro

Conceitualmente, um filtro compara instâncias de bug com um conjunto de critérios. Ao definir um filtro, você pode selecionar um tratamento especial para instâncias de bugs, como excluí-las ou incluí-las em um reporte.

Um arquivo de filtro é um documento XML com o elemento de nível superior FindBugsFilter, que possui um número de elementos Match como filhos. Cada elemento Match representa uma premissa a ser aplicada na geração de instâncias de bug. Geralmente, um filtro é usado para excluir instâncias de bug. Por exemplo:

$ spotbugs -textui -exclude myExcludeFilter.xml myApp.jar

No entanto, um filtro também pode ser usado para selecionar instâncias de bug para um reporte específico:

$ spotbugs -textui -include myIncludeFilter.xml myApp.jar

Os filhos dos elementos Match são conjuntos de premissas. Em outras palavras, cada filho deve ser verdadeiro true``para que a premissa seja verdadeira ``true.

Tipos de cláusulas Match

<Bug>

Este elemento especifica um ou mais padrões (pattern ou patterns) de um bug a serem comparados. O atributo pattern é uma lista, separada por vírgulas, contendo os tipos de padrões de bug. Você pode encontrar os tipos de padrões de bug ao procurar avisos específicos na saída produzida pela opção -xml (o atributo type do elemento BugInstances) ou a partir da Descrição de bugs.

For more coarse-grained matching, use code attribute. It takes a comma-separated list of bug abbreviations. For most-coarse grained matching use category attribute, that takes a comma separated list of bug category names: CORRECTNESS, MT_CORRECTNESS, BAD_PRACTICE, PERFORMANCE, STYLE.

Se mais de um dos atributos mencionados acima forem especificados no mesmo elemento <Bug>, todos os padrões de bug que correspondem a um dos nomes de padrão, abreviações ou categorias, serão correspondidos.

Como medida de compatibilidade com versões anteriores, os elementos <BugPattern> e <BugCode> podem ser usados em vez do elemento <Bug>. Cada um deles usa o atributo nome para especificar a lista de valores aceitos. O suporte para esses elementos pode ser removido em uma versão futura.

<Confidence>

Este elemento corresponde os avisos de bug com os níveis de confiança. O atributo value deve ser um valor inteiro: 1 corresponde ao nível de confiança alta , 2 corresponde ao nível de confiança normal e 3 corresponde ao nível de confiança baixa.O elemento <Confidence> substituiu o atributo <Priority> na versão 2.0.0.

<Priority>

Equivalente ao elemento <Confidence>. Existe por motivos de compatibilidade com versões anteriores.

<Rank>

Este elemento corresponde os avisos com a classificação de bug especificada. O atributo value deve ser um valor inteiro entre 1 e 20, onde os valores de 1 a 4 indicam os bugs mais graves, de 5 a 9 os bugs graves, de 10 a 14 os bugs problemáticos e de 15 a 20 os bugs preocupantes.

<Package>

Este elemento corresponde os avisos com as classes dentro do pacote especificado utilizando o atributo name. Os pacotes aninhados não são incluídos (em conjunto com as linhas de importação Java). No entanto, a correspondência de vários pacotes pode ser alcançada facilmente usando regex para a correspondência de nomes.

<Class>

This element matches warnings associated with a particular class. The name attribute is used to specify the exact or regex match pattern for the class name. The role attribute is the class role.

Como medida de compatibilidade com versões anteriores, você pode usar o atributo class em um elemento Match para especificar o nome exato de uma classe ou o atributo classregex para especificar uma expressão regular para a correspondência com o nome da classe.

Se o elemento Match não contém um elemento Class, nem um atributo class / classregex, então a premissa será aplicada a todas as classes. Tal premissa pode identificar mais instâncias de bug do que você deseja, a menos que seja refinado ainda mais com o método apropriado ou premissas de campo.

<Source>

Este elemento corresponde os avisos com um arquivo de origem específico. O atributo name é usado para especificar o padrão de correspondência exata ou regex para o nome do arquivo de origem.

<Method>

Este elemento especifica um método. O atributo name é usado para especificar o padrão de correspondência exata ou regex para o nome do método. O atributo params é uma lista contendo os tipos de parâmetros do método separados por vírgulas. O atributo returns é o tipo de retorno do método. O atributo role é o papel do método. Em params e returns, os nomes das classes devem ser totalmente qualificados. (Por exemplo: "java.lang.String" instead of just "String".) Se um dos últimos atributos for especificado, o outro é necessário para criar a assinatura de método. Observe que você pode fornecer o atributo name, params e returns, ou todos os três. Dessa forma, você pode fornecer vários tipos de correspondências baseadas em nome e assinatura.

<Field>

Este elemento especifica um campo. O atributo name é usado para especificar o padrão de correspondência exata ou regex para o nome do campo. Você também pode filtrar os campos de acordo com sua assinatura - use o atributo type para especificar o tipo do campo qualificado. Você pode especificar um ou ambos os atributos para realizar correspondências baseadas em nome / assinatura. O atributo role é o papel do campo.

<Local>

Este elemento especifica uma variável local. O atributo name é usado para especificar o padrão de correspondência exata ou regex para o nome da variável local. Variáveis locais são variáveis definidas dentro de um método.

<Type>

Este elemento corresponde os avisos com um tipo específico. O atributo descriptor é usado para especificar o padrão de correspondência exata ou regex para o descritor de tipo. Se o descritor começar com o caractere ~, o resto do conteúdo do atributo é interpretado como uma expressão Java regular. O atributo role é o papel da classe, e o typeParameters são os tipos de parâmetro. Ambos de role e typeParameters são atributos opcionais.

<Or>

Este elemento combina cláusulas Match como disjuntas. Isto é, você pode colocar dois elementos Method em uma cláusula Or para identificar qualquer um dos métodos.

<And>

Este elemento combina cláusulas Match que devem ser avaliadas como verdadeiras true. Isto é, você pode colocar os elementos Bug e Confidence em uma cláusula And para identificar as instâncias de bug apenas com o nível de confiança estabelecido.

<Not>

Este elemento inverte os filhos incluídos em Match. Isto é, você pode colocar um elemento Bug em uma cláusula Not para identificar quaisquer instâncias de bus, com exceção da especificada na cláusula.

Correspondência entre nomes de elementos Java

Se o atributo name dos elementos Class, Source, Method or Field começar com o caracter ~, então o restante do conteúdo do atributo é interpretado com uma expressão Java regular que é comparada com os nomes dos elementos Java em questão.

Note that the pattern is matched against whole element name and therefore .* clauses need to be used at pattern beginning and/or end to perform substring matching.

Veja a documentação java.util.regex.Pattern para sintaxe de padrão.

Caveats

As cláusulas Match podem comparar apenas as informações que realmente estão contidas nas instâncias de bug. Cada instância de bug possui uma classe, então a exclusão de bugs por classes funcionará.

Algumas instâncias de bug têm duas (ou mais) classes. Por exemplo, os bugs DE (dropped exception) reportam a classe que contém o método onde o dropped exception acontece e a classe que representa o tipo dropped exception. Somente a primeira classe (primária) é comparada com as cláusulas Match. Então, por exemplo, se você deseja suprimir os relatórios de IC (initialization circularity) para as classes “”com.foobar.A” e “com.foobar.B”, você usaria duas cláusulas Match:

<Match>
   <Class name="com.foobar.A" />
   <Bug code="IC" />
</Match>
<Match>
   <Class name="com.foobar.B" />
   <Bug code="IC" />
</Match>

Ao corresponder explicitamente as duas classes, você garante que a instância do bug IC será correspondida, independentemente de qual classe envolvida na circularidade seja listada primeiro na instância do bug. (Claro, esta abordagem pode suprimir acidentalmente circularidades envolvendo “com.foobar.A” ou “com.foobar.B” e uma terceira classe.)

Muitos tipos de bug relatam o método em que ocorrem. Para essas instâncias de bug, você pode colocar cláusulas Method no elemento Match e eles devem funcionar conforme o esperado.

Exemplos

Identificação de todos os bugs em uma classe

<Match>
  <Class name="com.foobar.MyClass" />
</Match>

Identificação de certos testes de uma classe por meio da especificação de suas abreviações

<Match>
  <Class name="com.foobar.MyClass"/ >
  <Bug code="DE,UrF,SIC" />
</Match>

Identificação de certos testes de todas as classes por meio da especificação de suas abreviações

<Match>
  <Bug code="DE,UrF,SIC" />
</Match>

Identificação de certos testes de todas as classes por meio da especificação de sua categoria

<Match>
  <Bug category="PERFORMANCE" />
</Match>

Identificação de tipos de bug de métodos especificados de uma classe por meio de suas abreviações

<Match>
  <Class name="com.foobar.MyClass" />
  <Or>
    <Method name="frob" params="int,java.lang.String" returns="void" />
    <Method name="blat" params="" returns="boolean" />
  </Or>
  <Bug code="DC" />
</Match>

Identificação de um padrão de bug em um método específico

<!-- A method with an open stream false positive. -->
<Match>
  <Class name="com.foobar.MyClass" />
  <Method name="writeDataToFile" />
  <Bug pattern="OS_OPEN_STREAM" />
</Match>

Identificação de um padrão de bug com prioridade em um método específico

<!-- A method with a dead local store false positive (medium priority). -->
<Match>
  <Class name="com.foobar.MyClass" />
  <Method name="someMethod" />
  <Bug pattern="DLS_DEAD_LOCAL_STORE" />
  <Priority value="2" />
</Match>

Identificação de minor bugs introduzidos pelo compilador do AspectJ (você provavelmente não está interessado nessa parte, a menos que seja um desenvolvedor Aspectj

<Match>
  <Class name="~.*\$AjcClosure\d+" />
  <Bug pattern="DLS_DEAD_LOCAL_STORE" />
  <Method name="run" />
</Match>
<Match>
  <Bug pattern="UUF_UNUSED_FIELD" />
  <Field name="~ajc\$.*" />
</Match>

Identificação de bugs em partes específicas do código base

<!-- match unused fields warnings in Messages classes in all packages -->
<Match>
  <Class name="~.*\.Messages" />
  <Bug code="UUF" />
</Match>
<!-- match mutable statics warnings in all internal packages -->
<Match>
  <Package name="~.*\.internal" />
  <Bug code="MS" />
</Match>
<!-- match anonymous inner classes warnings in ui package hierarchy -->
<Match>
  <Package name="~com\.foobar\.fooproject\.ui.*" />
  <Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON" />
</Match>

Identificação de bugs em campos e métodos com assinaturas específicas

<!-- match System.exit(...) usage warnings in void main(String[]) methods in all classes -->
<Match>
  <Method returns="void" name="main" params="java.lang.String[]" />
  <Bug pattern="DM_EXIT" />
</Match>
<!-- match UuF warnings on fields of type com.foobar.DebugInfo on all classes -->
<Match>
  <Field type="com.foobar.DebugInfo" />
  <Bug code="UuF" />
</Match>

Identificação de bugs usando o operador de filtro Not

<!-- ignore all bugs in test classes, except for those bugs specifically relating to JUnit tests -->
<!-- i.e. filter bug if ( classIsJUnitTest && ! bugIsRelatedToJUnit ) -->
<Match>
  <!-- the Match filter is equivalent to a logical 'And' -->

  <Class name="~.*\.*Test" />
  <!-- test classes are suffixed by 'Test' -->

  <Not>
      <Bug code="IJU" /> <!-- 'IJU' is the code for bugs related to JUnit test code -->
  </Not>
</Match>

Arquivo de filtro de exclusão completo para identificação de todas as classes geradas a partir de arquivos do Groovy

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Match>
  <Source name="~.*\.groovy" />
</Match>
</FindBugsFilter>

Exemplo completo

  <?xml version="1.0" encoding="UTF-8"?>
  <FindBugsFilter
              xmlns="https://github.com/spotbugs/filter/4.8.4"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="https://github.com/spotbugs/filter/4.8.4 https://raw.githubusercontent.com/spotbugs/spotbugs/4.8.4/spotbugs/etc/findbugsfilter.xsd">
  <Match>
    <Class name="com.foobar.ClassNotToBeAnalyzed" />
  </Match>

  <Match>
    <Class name="com.foobar.ClassWithSomeBugsMatched" />
    <Bug code="DE,UrF,SIC" />
  </Match>

  <!-- Match all XYZ violations. -->
  <Match>
    <Bug code="XYZ" />
  </Match>

  <!-- Match all doublecheck violations in these methods of "AnotherClass". -->
  <Match>
    <Class name="com.foobar.AnotherClass" />
    <Or>
      <Method name="nonOverloadedMethod" />
      <Method name="frob" params="int,java.lang.String" returns="void" />
      <Method name="blat" params="" returns="boolean" />
    </Or>
    <Bug code="DC" />
  </Match>

  <!-- A method with a dead local store false positive (medium priority). -->
  <Match>
    <Class name="com.foobar.MyClass" />
    <Method name="someMethod" />
    <Bug pattern="DLS_DEAD_LOCAL_STORE" />
    <Priority value="2" />
  </Match>

  <!-- All bugs in test classes, except for JUnit-specific bugs -->
  <Match>
  <Class name="~.*\.*Test" />
  <Not>
    <Bug code="IJU" />
  </Not>
  </Match>
</FindBugsFilter>