Comment désactiver une règle de contrôle particulière pour une ligne de code particulière?

185

J'ai une règle de validation de checkstyle configurée dans mon projet, qui interdit de définir des méthodes de classe avec plus de 3 paramètres d'entrée. La règle fonctionne bien pour mes classes, mais parfois je dois étendre des classes tierces, qui n'obéissent pas à cette règle particulière.

Existe-t-il une possibilité de demander à "checkstyle" qu'une certaine méthode doit être ignorée en silence?

BTW, j'ai fini avec mon propre wrapper de checkstyle: qulice.com (voir Contrôle strict de la qualité du code Java )

yegor256
la source

Réponses:

292

Découvrez l'utilisation de supressionCommentFilter sur http://checkstyle.sourceforge.net/config_filters.html#SuppressionCommentFilter . Vous devrez ajouter le module à votre checkstyle.xml

<module name="SuppressionCommentFilter"/>

et c'est configurable. Ainsi, vous pouvez ajouter des commentaires à votre code pour désactiver le checkstyle (à différents niveaux) puis le réactiver en utilisant des commentaires dans votre code. Par exemple

//CHECKSTYLE:OFF
public void someMethod(String arg1, String arg2, String arg3, String arg4) {
//CHECKSTYLE:ON

Ou encore mieux, utilisez cette version plus peaufinée:

<module name="SuppressionCommentFilter">
    <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
    <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
    <property name="checkFormat" value="$1"/>
</module>

qui vous permet de désactiver des vérifications spécifiques pour des lignes de code spécifiques:

//CHECKSTYLE.OFF: IllegalCatch - Much more readable than catching 7 exceptions
catch (Exception e)
//CHECKSTYLE.ON: IllegalCatch

* Remarque: vous devrez également ajouter FileContentsHolder:

<module name="FileContentsHolder"/>

Voir également

<module name="SuppressionFilter">
    <property name="file" value="docs/suppressions.xml"/>
</module>

sous la SuppressionFiltersection de cette même page, qui vous permet de désactiver les vérifications individuelles des ressources correspondant au modèle.

Donc, si vous avez dans votre checkstyle.xml:

<module name="ParameterNumber">
   <property name="id" value="maxParameterNumber"/>
   <property name="max" value="3"/>
   <property name="tokens" value="METHOD_DEF"/>
</module>

Vous pouvez le désactiver dans votre fichier xml de suppression avec:

<suppress id="maxParameterNumber" files="YourCode.java"/>

Une autre méthode, désormais disponible dans Checkstyle 5.7, consiste à supprimer les violations via l' @SuppressWarningsannotation java. Pour ce faire, vous devrez ajouter deux nouveaux modules ( SuppressWarningsFilteret SuppressWarningsHolder) dans votre fichier de configuration:

<module name="Checker">
   ...
   <module name="SuppressWarningsFilter" />
   <module name="TreeWalker">
       ...
       <module name="SuppressWarningsHolder" />
   </module>
</module> 

Ensuite, dans votre code, vous pouvez effectuer les opérations suivantes:

@SuppressWarnings("checkstyle:methodlength")
public void someLongMethod() throws Exception {

ou, pour plusieurs suppressions:

@SuppressWarnings({"checkstyle:executablestatementcount", "checkstyle:methodlength"})
public void someLongMethod() throws Exception {

NB: Le checkstyle:préfixe " " est facultatif (mais recommandé). Selon la documentation, le nom du paramètre doit être en minuscules, mais la pratique indique que tous les cas fonctionnent.

Chris Knight
la source
7
N'oubliez pas d'ajouter FileContentsHolder sur TreeWalter. Voir stackoverflow.com/a/5764666/480483
djjeck
2
si vous l'utilisez //CHECKSTYLE.OFF: puis oubliez de le réactiver, restera-t-il coché uniquement dans le fichier contenant //CHECKSTYLE.OFF: ou dans tous les fichiers traités ultérieurement?
Roland
1
@Roland, il reste éteint juste pour la durée de cette classe de test.
Chris Knight
1
"le nom du paramètre doit être en minuscules." @SuppressWarnings("checkstyle:VariableDeclarationUsageDistance")fonctionnait aussi bien pour moi que l'équivalent en minuscules.
Anders Rabo Thorbeck
2
Depuis checkstyle 8.1 le SuppressionCommentFilter devrait être sous la TreeWalker, et FileContentHoldern'est pas nécessaire (disponible) plus.
avandeursen
71

Si vous préférez utiliser des annotations pour faire taire les règles de manière sélective, cela est désormais possible en utilisant l' @SuppressWarningsannotation, à partir de Checkstyle 5.7 (et pris en charge par Checkstyle Maven Plugin 2.12+).

Tout d'abord, dans votre checkstyle.xml, ajoutez le SuppressWarningsHoldermodule au TreeWalker:

<module name="TreeWalker">
    <!-- Make the @SuppressWarnings annotations available to Checkstyle -->
    <module name="SuppressWarningsHolder" />
</module>

Ensuite, activez le SuppressWarningsFilterlà (en tant que frère de TreeWalker):

<!-- Filter out Checkstyle warnings that have been suppressed with the @SuppressWarnings annotation -->
<module name="SuppressWarningsFilter" />

<module name="TreeWalker">
...

Vous pouvez maintenant annoter, par exemple, la méthode que vous souhaitez exclure d'une certaine règle Checkstyle:

@SuppressWarnings("checkstyle:methodlength")
@Override
public boolean equals(Object obj) {
    // very long auto-generated equals() method
}

Le checkstyle:préfixe dans l'argument to @SuppressWarningsest facultatif, mais je l'aime comme un rappel d'où vient cet avertissement. Le nom de la règle doit être en minuscules.

Enfin, si vous utilisez Eclipse, il se plaindra du fait que l'argument lui est inconnu:

Non pris en charge @SuppressWarnings ("checkstyle: methodlength")

Vous pouvez désactiver cet avertissement Eclipse dans les préférences si vous le souhaitez:

Preferences:
  Java
  --> Compiler
  --> Errors/Warnings
  --> Annotations
  --> Unhandled token in '@SuppressWarnings': set to 'Ignore'
Henrik Heimbuerger
la source
2
Je nomme ceci comme réponse vérifiée, car je pense que c'est la solution qui devrait fonctionner le mieux dans la plupart des cas.
avandeursen
34

Ce qui fonctionne également bien est le SuppressWithNearbyCommentFilter qui utilise des commentaires individuels pour supprimer les événements d'audit.

Par exemple

// CHECKSTYLE IGNORE check FOR NEXT 1 LINES
public void onClick(View view) { ... }

Pour configurer un filtre afin que CHECKSTYLE IGNORE check FOR NEXT var LINES évite de déclencher des audits pour le check donné pour la ligne courante et les prochaines var lines (pour un total de var + 1 lignes):

<module name="SuppressWithNearbyCommentFilter">
    <property name="commentFormat" value="CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINES"/>
    <property name="checkFormat" value="$1"/>
    <property name="influenceFormat" value="$2"/>
</module>

http://checkstyle.sourceforge.net/config.html

Akos Cz
la source
Je changerais l'expression régulière pour CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINES?rendre la commande ignorer plus lisible. (Vous pourrez utiliser "CHECKSTYLE IGNORE check FOR NEXT 1 LINE" et "CHECKSTYLE IGNORE check FOR NEXT 3 LINES").
Matt3o12
@ matt3o12 CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINEfonctionne aussi pour moi (il correspond à la fois lineet lines).
Slava Semushin
4

Chaque réponse faisant référence à SuppressWarningsFilter manque un détail important. Vous ne pouvez utiliser l'ID tout en minuscules que s'il est défini comme tel dans votre checkstyle-config.xml. Sinon, vous devez utiliser le nom du module d'origine.

Par exemple, si dans mon checkstyle-config.xml j'ai:

<module name="NoWhitespaceBefore"/>

Je ne peux pas utiliser:

@SuppressWarnings({"nowhitespacebefore"})

Je dois cependant utiliser:

@SuppressWarnings({"NoWhitespaceBefore"})

Pour que la première syntaxe fonctionne, le checkstyle-config.xml doit avoir:

<module name="NoWhitespaceBefore">
  <property name="id" value="nowhitespacebefore"/>
</module>

C'est ce qui a fonctionné pour moi, du moins dans la version 6.17 de CheckStyle.

Joao Baltazar
la source
1

J'ai eu des difficultés avec les réponses ci-dessus, potentiellement parce que j'ai défini les avertissements checkStyle comme des erreurs. Ce qui a fonctionné était SuppressionFilter: http://checkstyle.sourceforge.net/config_filters.html#SuppressionFilter

L'inconvénient est que la plage de lignes est stockée dans un fichier suppresssions.xml séparé, de sorte qu'un développeur inconnu peut ne pas établir immédiatement la connexion.

Saltymule
la source
Merci, c'est la seule chose qui a fonctionné pour moi aussi
jonathanrz
1
<module name="Checker">
    <module name="SuppressionCommentFilter"/>
    <module name="TreeWalker">
        <module name="FileContentsHolder"/>
    </module>
</module>

Pour configurer un filtre pour supprimer les événements d'audit entre un commentaire contenant la ligne BEGIN GENERATED CODE et un commentaire contenant la ligne END GENERATED CODE:

<module name="SuppressionCommentFilter">
  <property name="offCommentFormat" value="BEGIN GENERATED CODE"/>
  <property name="onCommentFormat" value="END GENERATED CODE"/>
</module>

//BEGIN GENERATED CODE
@Override
public boolean equals(Object obj) { ... } // No violation events will be reported

@Override
public int hashCode() { ... } // No violation events will be reported
//END GENERATED CODE

En savoir plus

Roberto
la source
0

Vous pouvez essayer https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathFilter

Vous pouvez le configurer comme:


<module name="SuppressionXpathFilter">
  <property name="file" value="suppressions-xpath.xml"/>
  <property name="optional" value="false"/>
</module>
        

Générez des suppressions Xpath à l'aide de l'interface de ligne de commande avec l'option -g et spécifiez la sortie à l'aide du commutateur -o.

https://checkstyle.sourceforge.io/cmdline.html#Command_line_usage

Voici un extrait de code qui vous aidera à configurer votre génération automatique de suppressions Checkstyle:


<target name="checkstyleg">
    <move file="suppressions-xpath.xml"
      tofile="suppressions-xpath.xml.bak"
      preservelastmodified="true"
      force="true"
      failonerror="false"
      verbose="true"/>
    <fileset dir="${basedir}"
                    id="javasrcs">
    <include name="**/*.java" />
    </fileset>
    <pathconvert property="sources"
                            refid="javasrcs"
                            pathsep=" " />
    <loadfile property="cs.cp"
                        srcFile="../${cs.classpath.file}" />
    <java classname="${cs.main.class}"
                logError="true">
    <arg line="-c ../${cs.config} -p ${cs.properties} -o ${ant.project.name}-xpath.xml -g ${sources}" />
    <classpath>
        <pathelement path="${cs.cp}" />
        <pathelement path="${java.class.path}" />
    </classpath>
</java>
<condition property="file.is.empty" else="false">
     <length file="${ant.project.name}-xpath.xml" when="equal" length="0" />
   </condition>
   <if>
     <equals arg1="${file.is.empty}" arg2="false"/>
     <then>
     <move file="${ant.project.name}-xpath.xml"
      tofile="suppressions-xpath.xml"
      preservelastmodified="true"
      force="true"
      failonerror="true"
  verbose="true"/>
   </then>
</if>
    </target>

Suppressions-xpath.xml est spécifié comme source de suppression Xpath dans la configuration des règles Checkstyle. Dans l'extrait de code ci-dessus, je charge le chemin de classe Checkstyle à partir d'un fichier cs.cp dans une propriété. Vous pouvez choisir de spécifier directement le chemin de classe.

Ou vous pouvez utiliser groovy dans Maven (ou Ant) pour faire de même:


import java.nio.file.Files
import java.nio.file.StandardCopyOption  
import java.nio.file.Paths

def backupSuppressions() {
  def supprFileName = 
      project.properties["checkstyle.suppressionsFile"]
  def suppr = Paths.get(supprFileName)
  def target = null
  if (Files.exists(suppr)) {
    def supprBak = Paths.get(supprFileName + ".bak")
    target = Files.move(suppr, supprBak,
        StandardCopyOption.REPLACE_EXISTING)
    println "Backed up " + supprFileName
  }
  return target
}

def renameSuppressions() {
  def supprFileName = 
      project.properties["checkstyle.suppressionsFile"]
  def suppr = Paths.get(project.name + "-xpath.xml")
  def target = null
  if (Files.exists(suppr)) {
    def supprNew = Paths.get(supprFileName)
    target = Files.move(suppr, supprNew)
    println "Renamed " + suppr + " to " + supprFileName
  }
  return target
}

def getClassPath(classLoader, sb) {
  classLoader.getURLs().each {url->
     sb.append("${url.getFile().toString()}:")
  }
  if (classLoader.parent) {
     getClassPath(classLoader.parent, sb)
  }
  return sb.toString()
}

backupSuppressions()

def cp = getClassPath(this.class.classLoader, 
    new StringBuilder())
def csMainClass = 
      project.properties["cs.main.class"]
def csRules = 
      project.properties["checkstyle.rules"]
def csProps = 
      project.properties["checkstyle.properties"]

String[] args = ["java", "-cp", cp,
    csMainClass,
    "-c", csRules,
"-p", csProps,
"-o", project.name + "-xpath.xml",
"-g", "src"]

ProcessBuilder pb = new ProcessBuilder(args)
pb = pb.inheritIO()
Process proc = pb.start()
proc.waitFor()

renameSuppressions()

Le seul inconvénient de l'utilisation des suppressions Xpath --- en plus des vérifications qu'il ne prend pas en charge --- est si vous avez du code comme celui-ci:

package cstests;

public interface TestMagicNumber {
  static byte[] getAsciiRotator() {
    byte[] rotation = new byte[95 * 2];
    for (byte i = ' '; i <= '~'; i++) {
      rotation[i - ' '] = i;
      rotation[i + 95 - ' '] = i;
    }
    return rotation;
  }
}

La suppression Xpath générée dans ce cas n'est pas ingérée par Checkstyle et le vérificateur échoue avec une exception:

<suppress-xpath
       files="TestMagicNumber.java"
       checks="MagicNumberCheck"
       query="/INTERFACE_DEF[./IDENT[@text='TestMagicNumber']]/OBJBLOCK/METHOD_DEF[./IDENT[@text='getAsciiRotator']]/SLIST/LITERAL_FOR/SLIST/EXPR/ASSIGN[./IDENT[@text='i']]/INDEX_OP[./IDENT[@text='rotation']]/EXPR/MINUS[./CHAR_LITERAL[@text='' '']]/PLUS[./IDENT[@text='i']]/NUM_INT[@text='95']"/>

La génération de suppressions Xpath est recommandée lorsque vous avez corrigé toutes les autres violations et que vous souhaitez supprimer le reste. Il ne vous permettra pas de sélectionner des instances spécifiques dans le code à supprimer. Vous pouvez cependant sélectionner et choisir des suppressions dans le fichier généré pour cela.

SuppressionXpathSingleFilter est mieux adapté pour identifier et supprimer une règle, un fichier ou un message d'erreur spécifique. Vous pouvez configurer plusieurs filtres identifiant chacun d'eux par l'attribut id.

https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathSingleFilter

fernal73
la source