Как отключить конкретное правило контрольного стиля для определенной строки кода?

185

В моем проекте настроено правило проверки контрольного стиля , которое запрещает определять методы класса с более чем 3 входными параметрами. Правило отлично работает для моих классов, но иногда мне приходится расширять сторонние классы, которые не подчиняются этому конкретному правилу.

Есть ли возможность проинструктировать "checkstyle", что определенный метод должен быть тихо проигнорирован?

Кстати, у меня появилась своя собственная оболочка checkstyle: qulice.com (см. Строгий контроль качества кода Java )

yegor256
источник

Ответы:

292

Проверьте использование supressionCommentFilter по адресу http://checkstyle.sourceforge.net/config_filters.html#SuppressionCommentFilter . Вам нужно будет добавить модуль в ваш checkstyle.xml

<module name="SuppressionCommentFilter"/>

и это настраивается. Таким образом, вы можете добавить комментарии к своему коду, чтобы отключить контрольный стиль (на разных уровнях), а затем снова включить его, используя комментарии в вашем коде. Например

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

Или даже лучше, используйте эту более тонкую версию:

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

который позволяет отключить определенные проверки для определенных строк кода:

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

* Примечание: вам также нужно добавить FileContentsHolder:

<module name="FileContentsHolder"/>

Смотрите также

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

под SuppressionFilter разделе на той же странице, который позволяет отключить отдельные проверки для ресурсов, соответствующих шаблону.

Итак, если у вас есть в вашем checkstyle.xml:

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

Вы можете отключить его в вашем XML-файле подавления с помощью:

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

Другой метод, теперь доступный в Checkstyle 5.7, состоит в подавлении нарушений с помощью @SuppressWarningsjava-аннотации. Для этого вам необходимо добавить два новых модуля ( SuppressWarningsFilterи SuppressWarningsHolder) в ваш файл конфигурации:

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

Затем в своем коде вы можете сделать следующее:

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

или для многократных подавлений:

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

Примечание:checkstyle: префикс " " является необязательным (но рекомендуется). Согласно документам имя параметра должно быть написано строчными буквами, но практика показывает, что любой случай работает.

Крис Найт
источник
7
Не забудьте добавить FileContentsHolder на TreeWalter. См stackoverflow.com/a/5764666/480483
djjeck
2
если вы используете, //CHECKSTYLE.OFF: а затем забудете включить его снова, останется ли флажок только в файле, содержащем файл, //CHECKSTYLE.OFF: или во всех последующих обработанных файлах?
Роланд
1
@Roland, он остается выключенным только на время этого теста.
Крис Найт
1
msgstr "имя параметра должно быть в нижнем регистре." @SuppressWarnings("checkstyle:VariableDeclarationUsageDistance")работал так же хорошо для меня, как строчные эквиваленты.
Андерс Рабо Торбек,
2
Поскольку Checkstyle 8.1 SuppressionCommentFilter должен быть под TreeWalker, и FileContentHolderне надо (есть) больше.
avandeursen
71

Если вы предпочитаете использовать аннотации для выборочного молчания правил, теперь это возможно с помощью @SuppressWarnings аннотации, начиная с Checkstyle 5.7 (и поддерживается плагином Checkstyle Maven 2.12+).

Сначала checkstyle.xmlдобавьте SuppressWarningsHolderмодуль в TreeWalker:

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

Далее, включите SuppressWarningsFilterтам (как брат TreeWalker):

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

<module name="TreeWalker">
...

Теперь вы можете аннотировать, например, метод, который вы хотите исключить из определенного правила Checkstyle:

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

checkstyle:Префикс в аргументе не @SuppressWarningsявляется обязательным, но я , как это , как напоминание , где это предупреждение пришло. Имя правила должно быть в нижнем регистре.

Наконец, если вы используете Eclipse, он будет жаловаться на то, что аргумент ему неизвестен:

Неподдерживаемый @SuppressWarnings ("checkstyle: methodlength")

Вы можете отключить это предупреждение Eclipse в настройках, если вам нравится:

Preferences:
  Java
  --> Compiler
  --> Errors/Warnings
  --> Annotations
  --> Unhandled token in '@SuppressWarnings': set to 'Ignore'
Хенрик Хаймбюргер
источник
2
Я называю это проверенным ответом, так как считаю, что это решение должно работать лучше всего в большинстве случаев.
avandeursen
34

Также хорошо работает SuppressWithNearbyCommentFilter, который использует отдельные комментарии для подавления событий аудита.

Например

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

Чтобы настроить фильтр таким образом, чтобы проверка CHECKSTYLE IGNORE FOR NEXT var LINES позволяла избежать запуска любых проверок для данной проверки для текущей строки и следующих строк var (всего для строк var + 1):

<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
источник
Я бы изменил регулярное выражение, чтобы CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINES?сделать команду игнорирования более читабельной. (Вы сможете использовать «Проверка CHECKSTYLE IGNORE ДЛЯ СЛЕДУЮЩЕЙ 1 ЛИНИИ» и «Проверка CHECKSTYLE IGNORE ДЛЯ СЛЕДУЮЩИХ 3 ЛИНИЙ»).
Matt3o12
@ matt3o12 CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINEу меня тоже работает (совпадает и с lineи lines).
Слава Семушин
4

В каждом ответе на SuppressWarningsFilter отсутствует важная деталь. Вы можете использовать только строчный идентификатор, если он определен как таковой в вашем файле checkstyle-config.xml. Если нет, вы должны использовать оригинальное имя модуля.

Например, если в моем checkstyle-config.xml у меня есть:

<module name="NoWhitespaceBefore"/>

Я не могу использовать:

@SuppressWarnings({"nowhitespacebefore"})

Я должен, однако, использовать:

@SuppressWarnings({"NoWhitespaceBefore"})

Для того, чтобы первый синтаксис работал, checkstyle-config.xml должен иметь:

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

Это то, что у меня сработало, по крайней мере, в версии CheckStyle 6.17.

Жоао Балтазар
источник
1

У меня были трудности с ответами выше, возможно потому, что я установил предупреждения checkStyle как ошибки. Что сработало, так это SuppressionFilter: http://checkstyle.sourceforge.net/config_filters.html#SuppressionFilter

Недостатком этого является то, что диапазон строк хранится в отдельном файле suppresssions.xml, поэтому незнакомый разработчик может не сразу установить соединение.

Saltymule
источник
Спасибо, это было единственное, что сработало и для меня
jonathanrz
1
<module name="Checker">
    <module name="SuppressionCommentFilter"/>
    <module name="TreeWalker">
        <module name="FileContentsHolder"/>
    </module>
</module>

Чтобы настроить фильтр для подавления событий аудита между комментарием, содержащим строку BEGIN GENERATED CODE, и комментарием, содержащим строку 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

Узнать больше

Роберто
источник
0

Вы можете попробовать https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathFilter

Вы можете настроить его как:


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

Сгенерируйте подавления Xpath, используя CLI с опцией -g, и укажите выходные данные, используя ключ -o.

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

Вот фрагмент кода муравья, который поможет вам настроить автогенерацию подавления 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 указывается в качестве источника подавлений Xpath в конфигурации правил Checkstyle. В приведенном выше фрагменте я загружаю путь класса Checkstyle из файла cs.cp в свойство. Вы можете указать путь к классу напрямую.

Или вы можете использовать groovy в Maven (или Ant), чтобы сделать то же самое:


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()

Единственный недостаток использования подавлений Xpath - помимо проверок, которые он не поддерживает - это если у вас есть код, подобный следующему:

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;
  }
}

Подавление Xpath, сгенерированное в этом случае, не принимается Checkstyle, и проверка завершается с ошибкой с исключением:

<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']"/>

Генерация подавлений Xpath рекомендуется, когда вы исправили все другие нарушения и хотите подавить все остальные. Это не позволит вам выбрать конкретные экземпляры в коде для подавления. Вы можете, однако, выбрать и выбрать подавления из сгенерированного файла, чтобы сделать именно это.

SuppressionXpathSingleFilter лучше подходит для идентификации и подавления определенного правила, файла или сообщения об ошибке. Вы можете настроить несколько фильтров, идентифицирующих каждый по атрибуту id.

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

fernal73
источник