diff --git a/.ci/jsoref-spellchecker/whitelist.words b/.ci/jsoref-spellchecker/whitelist.words index 81b711471f0..a4ed7c91e20 100644 --- a/.ci/jsoref-spellchecker/whitelist.words +++ b/.ci/jsoref-spellchecker/whitelist.words @@ -521,7 +521,7 @@ gzip hadoop hamcrest Haml -Hardcoded +hardcoded hashcode hashset hashtable @@ -630,6 +630,7 @@ javadoctags javadoctype javadocvariable Javaee +javaformat javaguide javall javamail @@ -1194,6 +1195,7 @@ suppressionfilter suppressionsloader suppressionsstringprinter suppressionxpathfilter +suppressionxpathsinglefilter suppresswarnings suppresswarningsfilter suppresswarningsholder diff --git a/config/checkstyle_checks.xml b/config/checkstyle_checks.xml index af3b9f5e115..23236b224d8 100644 --- a/config/checkstyle_checks.xml +++ b/config/checkstyle_checks.xml @@ -350,6 +350,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/pmd-test.xml b/config/pmd-test.xml index 75fb33565b9..51a1baad9a4 100644 --- a/config/pmd-test.xml +++ b/config/pmd-test.xml @@ -193,4 +193,17 @@ + + + + + + diff --git a/config/spotbugs-exclude.xml b/config/spotbugs-exclude.xml index a009ef39395..593779557eb 100644 --- a/config/spotbugs-exclude.xml +++ b/config/spotbugs-exclude.xml @@ -78,6 +78,9 @@ + + diff --git a/config/suppressions.xml b/config/suppressions.xml index 5ac8143767f..b7ac7d405f9 100644 --- a/config/suppressions.xml +++ b/config/suppressions.xml @@ -28,12 +28,8 @@ - - - - @@ -44,11 +40,6 @@ - - - - - @@ -70,7 +61,6 @@ - diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java index 78d15e3c667..c48abb34bab 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java @@ -843,6 +843,8 @@ private static void fillModulesFromFiltersPackage() { BASE_PACKAGE + ".filters.SuppressionFilter"); NAME_TO_FULL_MODULE_NAME.put("SuppressionXpathFilter", BASE_PACKAGE + ".filters.SuppressionXpathFilter"); + NAME_TO_FULL_MODULE_NAME.put("SuppressionXpathSingleFilter", + BASE_PACKAGE + ".filters.SuppressionXpathSingleFilter"); NAME_TO_FULL_MODULE_NAME.put("SuppressWarningsFilter", BASE_PACKAGE + ".filters.SuppressWarningsFilter"); NAME_TO_FULL_MODULE_NAME.put("SuppressWithNearbyCommentFilter", diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java index 504cdbb1ab0..d889a767777 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java @@ -212,7 +212,8 @@ * * *

- * Note: a suppression filter is needed because + * Note: a + * suppression xpath single filter is needed because * IDEA has no blank line between "javax" and "java". * ImportOrder has a limitation by design to enforce an empty line between groups ("java", "javax"). * There is no flexibility to enforce empty lines between some groups and no empty lines between @@ -230,17 +231,10 @@ * <property name="option" value="bottom"/> * <property name="sortStaticImportsAlphabetically" value="true"/> * </module> - * - *

- * <?xml version="1.0"?>
- * <!DOCTYPE suppressions PUBLIC
- *     "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
- *     "https://checkstyle.org/dtds/suppressions_1_2.dtd">
- *
- * <suppressions>
- *     <!-- message contains no message text to work well in multi-language environments -->
- *     <suppress checks="ImportOrder" message="^'java\..*'.*"/>
- * </suppressions>
+ * <module name="SuppressionXpathSingleFilter">
+ *   <property name="checks" value="ImportOrder"/>
+ *   <property name="message" value="^'java\..*'.*"/>
+ * </module>
  * 
*

* To configure the check so that it matches default NetBeans formatter configuration diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilter.java b/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilter.java new file mode 100644 index 00000000000..20654c667b3 --- /dev/null +++ b/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilter.java @@ -0,0 +1,127 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.filters; + +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; +import com.puppycrawl.tools.checkstyle.api.AutomaticBean; + +/** + * Filter {@code SuppressionXpathSingleFilter} suppresses audit events for + * Checks violations in the specified file, class, checks, message, module id, + * and xpath. + * Attention: This filter only supports single suppression, and will need + * multiple instances if users wants to suppress multiple violations. + */ +public class SuppressionXpathSingleFilter extends AutomaticBean implements + TreeWalkerFilter { + /** + * XpathFilter instance. + */ + private XpathFilter xpathFilter; + /** + * The pattern for file names. + */ + private Pattern files; + /** + * The pattern for check class names. + */ + private Pattern checks; + /** + * The pattern for message names. + */ + private Pattern message; + /** + * Module id of filter. + */ + private String id; + /** + * Xpath query. + */ + private String query; + + /** + * Set the regular expression to specify names of files to suppress. + * @param files the name of the file + */ + public void setFiles(String files) { + if (files == null) { + this.files = null; + } + else { + this.files = Pattern.compile(files); + } + } + + /** + * Set the regular expression to specify the name of the check to suppress. + * @param checks the name of the check + */ + public void setChecks(String checks) { + if (checks == null) { + this.checks = null; + } + else { + this.checks = Pattern.compile(checks); + } + } + + /** + * Set the regular expression to specify the message of the check to suppress. + * @param message the message of the check + */ + public void setMessage(String message) { + if (message == null) { + this.message = null; + } + else { + this.message = Pattern.compile(message); + } + } + + /** + * Set the ID of the check to suppress. + * @param id the ID of the check + */ + public void setId(String id) { + this.id = id; + } + + /** + * Set the xpath query. + * @param query the xpath query + */ + public void setQuery(String query) { + this.query = query; + } + + @Override + protected void finishLocalSetup() { + xpathFilter = new XpathFilter(files, checks, message, id, query); + } + + @Override + public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) { + return xpathFilter.accept(treeWalkerAuditEvent); + } + +} diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java b/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java index 202883f4a8f..f7931e42041 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java @@ -111,7 +111,57 @@ public XpathFilter(String files, String checks, xpathExpression = xpathEvaluator.createExpression(xpathQuery); } catch (XPathException ex) { - throw new IllegalStateException("Unexpected xpath query: " + xpathQuery, ex); + throw new IllegalArgumentException("Unexpected xpath query: " + xpathQuery, ex); + } + } + } + + /** + * Creates a {@code XpathElement} instance. + * @param files regular expression for names of filtered files + * @param checks regular expression for filtered check classes + * @param message regular expression for messages. + * @param moduleId the module id + * @param query the xpath query + */ + public XpathFilter(Pattern files, Pattern checks, Pattern message, + String moduleId, String query) { + if (files == null) { + filePattern = null; + fileRegexp = null; + } + else { + filePattern = files.pattern(); + fileRegexp = files; + } + if (checks == null) { + checkPattern = null; + checkRegexp = null; + } + else { + checkPattern = checks.pattern(); + checkRegexp = checks; + } + if (message == null) { + messagePattern = null; + messageRegexp = null; + } + else { + messagePattern = message.pattern(); + messageRegexp = message; + } + this.moduleId = moduleId; + xpathQuery = query; + if (xpathQuery == null) { + xpathExpression = null; + } + else { + final XPathEvaluator xpathEvaluator = new XPathEvaluator(); + try { + xpathExpression = xpathEvaluator.createExpression(xpathQuery); + } + catch (XPathException ex) { + throw new IllegalArgumentException("Incorrect xpath query: " + xpathQuery, ex); } } } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilterTest.java new file mode 100644 index 00000000000..b97e83d421f --- /dev/null +++ b/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilterTest.java @@ -0,0 +1,303 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.filters; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.nio.charset.StandardCharsets; + +import org.junit.Before; +import org.junit.Test; + +import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport; +import com.puppycrawl.tools.checkstyle.JavaParser; +import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; +import com.puppycrawl.tools.checkstyle.api.FileContents; +import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +public class SuppressionXpathSingleFilterTest + extends AbstractModuleTestSupport { + + private File file; + private FileContents fileContents; + + @Before + public void setUp() throws Exception { + file = new File(getPath("InputSuppressionXpathSingleFilter.java")); + fileContents = new FileContents(new FileText(file, + StandardCharsets.UTF_8.name())); + } + + @Override + protected String getPackageLocation() { + return "com/puppycrawl/tools/checkstyle/filters/suppressionxpathsinglefilter"; + } + + @Test + public void testMatching() throws Exception { + final String xpath = "/CLASS_DEF[@text='InputSuppressionXpathSingleFilter']"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + final TreeWalkerAuditEvent ev = createEvent(3, 0, + TokenTypes.CLASS_DEF); + assertFalse("Event should be rejected", filter.accept(ev)); + } + + @Test + public void testNonMatchingTokenType() throws Exception { + final String xpath = "//METHOD_DEF[@text='countTokens']"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + final TreeWalkerAuditEvent ev = createEvent(3, 0, + TokenTypes.CLASS_DEF); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testNonMatchingLineNumber() throws Exception { + final String xpath = "/CLASS_DEF[@text='InputSuppressionXpathSingleFilter']"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + final TreeWalkerAuditEvent ev = createEvent(100, 0, + TokenTypes.CLASS_DEF); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testNonMatchingColumnNumber() throws Exception { + final String xpath = "/CLASS_DEF[@text='InputSuppressionXpathSingleFilter']"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + final TreeWalkerAuditEvent ev = createEvent(3, 100, + TokenTypes.CLASS_DEF); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testComplexQuery() throws Exception { + final String xpath = "//VARIABLE_DEF[@text='pi' and " + + "../..[@text='countTokens']] " + + "| //VARIABLE_DEF[@text='someVariable' and ../..[@text='sum']]"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + final TreeWalkerAuditEvent eventOne = createEvent(5, 8, + TokenTypes.VARIABLE_DEF); + final TreeWalkerAuditEvent eventTwo = createEvent(10, 4, + TokenTypes.VARIABLE_DEF); + final TreeWalkerAuditEvent eventThree = createEvent(15, 8, + TokenTypes.VARIABLE_DEF); + assertFalse("Event should be rejected", filter.accept(eventOne)); + assertTrue("Event should be accepted", filter.accept(eventTwo)); + assertFalse("Event should be rejected", filter.accept(eventThree)); + } + + @Test + public void testIncorrectQuery() { + final String xpath = "1@#"; + try { + final Object test = createSuppressionXpathSingleFilter( + "InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + fail("Exception was expected but got " + test); + } + catch (IllegalArgumentException ex) { + assertTrue("Message should be: Unexpected xpath query", + ex.getMessage().contains("Incorrect xpath query")); + } + } + + @Test + public void testNoQuery() throws Exception { + final TreeWalkerAuditEvent event = createEvent(15, 8, + TokenTypes.VARIABLE_DEF); + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, null); + assertFalse("Event should be accepted", filter.accept(event)); + } + + @Test + public void testNullFileName() { + final String xpath = "NON_MATCHING_QUERY"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(null, + null, null, null); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testNonMatchingFileRegexp() throws Exception { + final String xpath = "NON_MATCHING_QUERY"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("NonMatchingRegexp", "Test", + null, null, xpath); + final TreeWalkerAuditEvent ev = createEvent(3, 0, + TokenTypes.CLASS_DEF); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testNullLocalizedMessage() { + final String xpath = "NON_MATCHING_QUERY"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, null, xpath); + final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(null, + file.getName(), null, null); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testNonMatchingModuleId() throws Exception { + final String xpath = "NON_MATCHING_QUERY"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, "id19", xpath); + final LocalizedMessage message = + new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", "", + null, null, "id20", + getClass(), null); + final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(), + message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS)); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testMatchingModuleId() throws Exception { + final String xpath = "/CLASS_DEF[@text='InputSuppressionXpathSingleFilter']"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test", + null, "id19", xpath); + final LocalizedMessage message = + new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", + "", null, null, "id19", + getClass(), null); + final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(), + message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS)); + assertFalse("Event should be rejected", filter.accept(ev)); + } + + @Test + public void testNonMatchingChecks() throws Exception { + final String xpath = "NON_MATCHING_QUERY"; + final SuppressionXpathSingleFilter filter = createSuppressionXpathSingleFilter( + "InputSuppressionXpathSingleFilter", "NonMatchingRegexp", + null, "id19", xpath); + final LocalizedMessage message = + new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", + "", null, null, "id19", + getClass(), null); + final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(), + message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS)); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testNonMatchingFileNameModuleIdAndCheck() throws Exception { + final String xpath = "NON_MATCHING_QUERY"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", + null, null, null, xpath); + final TreeWalkerAuditEvent ev = createEvent(3, 0, + TokenTypes.CLASS_DEF); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testNullModuleIdAndNonMatchingChecks() throws Exception { + final String xpath = "NON_MATCHING_QUERY"; + final SuppressionXpathSingleFilter filter = createSuppressionXpathSingleFilter( + "InputSuppressionXpathSingleFilter", "NonMatchingRegexp", null, null, xpath); + final TreeWalkerAuditEvent ev = createEvent(3, 0, + TokenTypes.CLASS_DEF); + assertTrue("Event should be accepted", filter.accept(ev)); + } + + @Test + public void testDecideByMessage() throws Exception { + final LocalizedMessage message = new LocalizedMessage(0, 0, + TokenTypes.CLASS_DEF, "", "", + null, null, null, getClass(), "Test"); + final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(), + message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS)); + final SuppressionXpathSingleFilter filter1 = createSuppressionXpathSingleFilter( + null, null, "Test", null, null); + final SuppressionXpathSingleFilter filter2 = createSuppressionXpathSingleFilter( + null, null, "Bad", null, null); + assertFalse("Message match", filter1.accept(ev)); + assertTrue("Message not match", filter2.accept(ev)); + } + + @Test + public void testThrowException() { + final String xpath = "/CLASS_DEF[@text='InputSuppressionXpathSingleFilter']"; + final SuppressionXpathSingleFilter filter = + createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", + "Test", null, null, xpath); + final LocalizedMessage message = + new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", + "", null, null, "id19", + getClass(), null); + final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, + file.getName(), message, null); + try { + filter.accept(ev); + fail("Exception is expected"); + } + catch (IllegalStateException ex) { + assertTrue("Exception message does not match expected one", + ex.getMessage().contains("Cannot initialize context and evaluate query")); + } + } + + private static SuppressionXpathSingleFilter createSuppressionXpathSingleFilter( + String files, String checks, String message, String moduleId, String query) { + final SuppressionXpathSingleFilter filter = new SuppressionXpathSingleFilter(); + filter.setFiles(files); + filter.setChecks(checks); + filter.setMessage(message); + filter.setId(moduleId); + filter.setQuery(query); + filter.finishLocalSetup(); + return filter; + } + + private TreeWalkerAuditEvent createEvent(int line, int column, int tokenType) + throws Exception { + final LocalizedMessage message = + new LocalizedMessage(line, column, tokenType, "", "", null, null, null, + getClass(), null); + return new TreeWalkerAuditEvent(fileContents, file.getName(), message, + JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS)); + } + +} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterTest.java index 29547d0d7ed..7f5fb536329 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterTest.java @@ -125,7 +125,7 @@ public void testIncorrectQuery() { null, xpath); fail("Exception was expected but got " + test); } - catch (IllegalStateException ex) { + catch (IllegalArgumentException ex) { assertTrue("Message should be: Unexpected xpath query", ex.getMessage().contains("Unexpected xpath query")); } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/filters/suppressionxpathsinglefilter/InputSuppressionXpathSingleFilter.java b/src/test/resources/com/puppycrawl/tools/checkstyle/filters/suppressionxpathsinglefilter/InputSuppressionXpathSingleFilter.java new file mode 100644 index 00000000000..50389332766 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/filters/suppressionxpathsinglefilter/InputSuppressionXpathSingleFilter.java @@ -0,0 +1,19 @@ +package com.puppycrawl.tools.checkstyle.filters.suppressionxpathsinglefilter; + +public class InputSuppressionXpathSingleFilter { + private int countTokens() { + double pi = 3.14; + return 123; + } + + public String getName() { + int someVariable = 123; + return "InputSuppressByXpathThree"; + } + + public int sum(int a, int b) { + String someVariable = "Hello World"; + return a + b; + } + +} diff --git a/src/xdocs/config_filters.xml b/src/xdocs/config_filters.xml index d079a10f32a..c20f0acf9d7 100644 --- a/src/xdocs/config_filters.xml +++ b/src/xdocs/config_filters.xml @@ -887,7 +887,7 @@ public class UserService { a SuppressionXpathFilter to reject CyclomaticComplexity errors for all methods with name sayHelloWorld inside FileOne - and FileTwo classes: + and FileTwo files:

<?xml version="1.0"?> @@ -1011,6 +1011,401 @@ public class InputTest { +
+ +

Since Checkstyle 8.18

+

+ Filter SuppressionXpathSingleFilter suppresses audit events for + Checks violations in the specified file, class, checks, message, module id, + and xpath. +

+

+ Rationale: To allow users use suppressions configured in the same config with + other modules. SuppressionFilter and SuppressionXpathFilter are require separate + file. +

+

+ Advice: If checkstyle configuration is used for several projects, single suppressions + on common files/folders is better to put in checkstyle configuration as common rule. + All suppression that are for specific file names is better to keep in project specific + config file. +

+

+ Attention: This filter only supports single suppression, and will need + multiple instances if users wants to suppress multiple violations. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
namedescriptiontypedefault valuesince
filesa Regular Expression matched against the file name associated + with an audit eventRegular Expressionnull8.18
checksa Regular Expression matched against the name of the check + associated with an audit event.Regular Expressionnull8.18
messagea Regular Expression matched against the message of the check associated + with an audit event.Regular Expressionnull8.18
ida string matched against the ID of the check associated with an audit + event.Stringnull8.18
querya string xpath query.Stringnull8.18
+
+ +

+ To configure to suppress the MethodName check + for all methods with name MyMethod + inside FileOne and FileTwo files: +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="files" value="File(One|Two)\.java"/>
+  <property name="checks" value="MethodName"/>
+  <property name="query" value="(/CLASS_DEF[@text='FileOne']/OBJBLOCK/
+            METHOD_DEF[@text='MyMethod']/IDENT)|
+            (/CLASS_DEF[@text='FileTwo']/OBJBLOCK/METHOD_DEF[@text='MyMethod']/IDENT)"/>
+</module>
+        
+

Code example:

+
+public class FileOne {
+  public void MyMethod() {} // OK
+}
+
+public class FileTwo {
+  public void MyMethod() {} // OK
+}
+
+public class FileThree {
+  public void MyMethod() {} // violation, name 'MyMethod'
+                            // must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$'
+}
+        
+

+ To suppress MethodName check for method names matched pattern 'MyMethod[0-9]': +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value="MethodName"/>
+  <property name="message" value="MyMethod[0-9]"/>
+</module>
+        
+

Code Example:

+
+public class FileOne {
+  public void MyMethod1() {} // OK
+  public void MyMethod2() {} // OK
+  public void MyMethodA() {} // violation, name 'MyMethodA' must
+                             // match pattern '^[a-z](_?[a-zA-Z0-9]+)*$'
+}
+        
+

+ To suppress checks being specified by id property: +

+
+<module name="MethodName">
+  <property name="id" value="MethodName1"/>
+  <property name="format" value="^[a-z](_?[a-zA-Z0-9]+)*$"/>
+<module/>
+<module name="SuppressionXpathSingleFilter">
+  <property name="files" value="FileOne.java"/>
+  <property name="id" value="MethodName1"/>
+<module/>
+        
+

Code example:

+
+public class FileOne {
+  public void MyMethod() {} // OK
+}
+public class FileTwo {
+  public void MyMethod() {} // violation,  name 'MyMethod' must
+                            //match pattern '^[a-z](_?[a-zA-Z0-9]+)*$'
+}
+        
+

+ To suppress checks for all package definitions: +

+
+<module name="SuppressionXpathSingleFilter>
+  <property name="checks" value="PackageName"/>
+  <property name="query" query="/PACKAGE_DEF[@text='File']/IDENT"/>
+</module>
+        
+

Code example:

+
+package File; // OK
+
+public class FileOne {}
+        
+

+ To suppress RedundantModifier check for interface definitions: +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value="RedundantModifier"/>
+  <property name="query" value="/INTERFACE_DEF//*"/>
+<module/>
+        
+

Code Example:

+
+public interface TestClass {
+  public static final int CONSTANT1 = 1;  // OK
+}
+        
+

+ To suppress checks in the FileOne file by non-query: +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="files" value="FileOne.java"/>
+  <property name="checks" value="MyMethod"/>
+</module>
+        
+

Code example:

+
+public class FileOne {
+  public void MyMethod() {} // OK
+}
+
+public class FileTwo {
+  public void MyMethod() {} // violation, name 'MyMethod'
+                            // must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$'
+}
+        
+

+ Suppress checks for elements which are either class definitions, + either method definitions: +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value=".*"/>
+  <property name="query"
+            value="(/CLASS_DEF[@text='FileOne'])|
+            (/CLASS_DEF[@text='FileOne']/OBJBLOCK/METHOD_DEF[@text='MyMethod']/IDENT)"/>
+</module>
+        
+

Code example:

+
+abstract class FileOne { // OK
+  public void MyMethod() {} // OK
+}
+
+abstract class FileTwo { // violation of the AbstractClassName check,
+                         // it should match the pattern "^Abstract.+$"
+  public void MyMethod() {} // violation, name 'MyMethod'
+                            // must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$'
+}
+        
+

+ Suppress checks for MyMethod1 or MyMethod2 methods: +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value="MethodName"/>
+  <property name="query" value="/CLASS_DEF[@text='FileOne']/OBJBLOCK/
+            METHOD_DEF[@text='MyMethod1' or @text='MyMethod2']/IDENT"/>
+</module>
+        
+

Code example:

+
+public class FileOne {
+  public void MyMethod1() {} // OK
+  public void MyMethod2() {} // OK
+  public void MyMethod3() {} // violation, name 'MyMethod3' must
+                             // match pattern '^[a-z](_?[a-zA-Z0-9]+)*$'
+}
+        
+

+ Suppress checks for variable testVariable inside + testMethod method inside TestClass class: +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value="LocalFinalVariableName"/>
+  <property name="query" value="/CLASS_DEF[@text='TestClass']/OBJBLOCK
+        /METHOD_DEF[@text='testMethod']/SLIST
+        /VARIABLE_DEF[@text='testVariable1']/IDENT"/>
+</module>
+        
+

Code Example:

+
+public class TestClass {
+  public void testMethod() {
+    final int testVariable1 = 10; // OK
+    final int testVariable2 = 10; // violation of the LocalFinalVariableName check,
+                                  // name 'testVariable2' must match pattern '^[A-Z][A-Z0-9]*$'
+  }
+}
+        
+

+ In the following sample, violations for LeftCurly check + will be suppressed for classes with name Main or for methods + with name calculate. +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value="LeftCurly"/>
+  <property name="query" value="/CLASS_DEF[@text='TestClass']/OBJBLOCK
+        /METHOD_DEF[@text='testMethod1']/SLIST*"/>
+</module>
+        
+

Code Example:

+
+public class TestClass {
+  public void testMethod1()
+  { // OK
+  }
+
+  public void testMethod2()
+  { // violation, '{' should be on the previous line
+  }
+}
+        
+

+ The following example demonstrates how to suppress + RequireThis violations for variable age inside changeAge method. +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value="RequireThis"/>
+  <property name="query" value="/CLASS_DEF[@text='InputTest']
+        //METHOD_DEF[@text='changeAge']//ASSIGN[@text='age']/IDENT"/>
+</module>
+        
+

Code Example:

+
+public class InputTest {
+  private int age = 23;
+
+  public void changeAge() {
+    age = 24; // violation will be suppressed
+  }
+}
+        
+

+ Suppress IllegalThrows violations only for methods with name + throwsMethod and only for RuntimeException exceptions. + Double colon is used for axis iterations. In the following example ancestor + axis is used to iterate all ancestor nodes of the current node with type + METHOD_DEF and name throwsMethod. Please read more about xpath axes at + W3Schools Xpath Axes. +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value="IllegalThrows"/>
+  <property name="query" value="//LITERAL_THROWS/IDENT[
+          ..[@text='RuntimeException'] and ./ancestor::METHOD_DEF[@text='throwsMethod']]"/>
+</module>
+        
+

Code Example:

+
+public class InputTest {
+  public void throwsMethod() throws RuntimeException { // violation will be suppressed
+  }
+
+  public void sampleMethod() throws RuntimeException { // will throw violation here
+  }
+}
+        
+

+ The following sample demonstrates how to suppress all violations for method itself and + all descendants. descendant-or-self axis iterates through current node and + all children nodes at any level. Keyword node() selects node elements. + Please read more about xpath syntax at + W3Schools Xpath Syntax. +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="checks" value=".*"/>
+  <property name="query" value="//METHOD_DEF[@text='TestMethod1']
+        /descendant-or-self::node()"/>
+</module>
+        
+

Code Example:

+
+public class TestClass {
+  public void TestMethod1() { // OK
+    final int num = 10; // OK
+  }
+
+  public void TestMethod2() { // violation of the MethodName check,
+                              // name 'TestMethod2' must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$'
+    final int num = 10; // violation of the LocalFinalVariableName check,
+                        // name 'num' must match pattern '^[A-Z][A-Z0-9]*$'
+  }
+}
+        
+

+ The following example is an example of what checks would be suppressed + while building Spring projects with checkstyle plugin. + Please find more information at: + spring-javaformat +

+
+<module name="SuppressionXpathSingleFilter">
+  <property name="files" value="[\\/]src[\\/]test[\\/]java[\\/]"/>
+  <property name="checks" value="Javadoc*"/>
+</module>
+<module name="SuppressionXpathSingleFilter">
+  <property name="files" value=".*Tests\.java">
+  <property name="checks" value="Javadoc*">
+</module>
+<module name="SuppressionXpathSingleFilter">
+  <property name="files" value="generated-sources">
+  <property name="checks" value="[a-zA-Z0-9]*">
+</module>
+        
+
+ + + + +

com.puppycrawl.tools.checkstyle.filters

+
+ +

TreeWalker

+
+
+

Since Checkstyle 5.7

diff --git a/src/xdocs/config_imports.xml b/src/xdocs/config_imports.xml index 5b25fb5746d..d7df4929b3c 100644 --- a/src/xdocs/config_imports.xml +++ b/src/xdocs/config_imports.xml @@ -1554,7 +1554,8 @@ import java.util.stream.IntStream;
  • groups are separated by, at least, one blank line and aren't separated internally
  • -

    Note: a suppression filter +

    Note: a + suppression xpath single filter is needed because IDEA has no blank line between "javax" and "java". ImportOrder has a limitation by design to enforce an empty line between groups ("java", "javax"). There is no flexibility to enforce empty lines between some @@ -1571,18 +1572,10 @@ import java.util.stream.IntStream; <property name="option" value="bottom"/> <property name="sortStaticImportsAlphabetically" value="true"/> </module> - - - -<?xml version="1.0"?> -<!DOCTYPE suppressions PUBLIC - "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" - "https://checkstyle.org/dtds/suppressions_1_2.dtd"> - -<suppressions> - <!-- message contains no message text to work well in multi-language environments --> - <suppress checks="ImportOrder" message="^'java\..*'.*"/> -</suppressions> +<module name="SuppressionXpathSingleFilter"> + <property name="checks" value="ImportOrder"/> + <property name="message" value="^'java\..*'.*"/> +</module>

    To configure the check so that it matches default NetBeans formatter configuration