diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java index 3094faaef..18913dbf2 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java @@ -19,6 +19,7 @@ package com.puppycrawl.tools.checkstyle.checks.coding; import java.util.ArrayList; +import java.util.BitSet; import java.util.HashMap; import java.util.Iterator; import java.util.Set; @@ -42,6 +43,12 @@ public class MultipleStringLiteralsCheck extends Check * , with the ArrayList containing StringInfo objects. */ private final HashMap mStringMap = new HashMap(); + + /** + * Marks the TokenTypes where duplicate strings should be ignored. + */ + private final BitSet mIgnoreOccurrenceContext = new BitSet(); + /** * The allowed number of string duplicates in a file before an error is * generated. @@ -68,6 +75,7 @@ public class MultipleStringLiteralsCheck extends Check public MultipleStringLiteralsCheck() { setIgnoreStringsRegexp("^\"\"$"); + mIgnoreOccurrenceContext.set(TokenTypes.ANNOTATION); } /** @@ -86,6 +94,20 @@ public class MultipleStringLiteralsCheck extends Check } } + /** + * Adds a set of tokens the check is interested in. + * @param aStrRep the string representation of the tokens interested in + */ + public final void setIgnoreOccurrenceContext(String[] aStrRep) + { + mIgnoreOccurrenceContext.clear(); + for (int i = 0; i < aStrRep.length; i++) { + final String s = aStrRep[i]; + final int type = TokenTypes.getTokenId(s); + mIgnoreOccurrenceContext.set(type); + } + } + /** {@inheritDoc} */ public int[] getDefaultTokens() { @@ -95,6 +117,9 @@ public class MultipleStringLiteralsCheck extends Check /** {@inheritDoc} */ public void visitToken(DetailAST aAST) { + if (isInIgnoreOccurrenceContext(aAST)) { + return; + } final String currentString = aAST.getText(); if ((mPattern == null) || !mPattern.matcher(currentString).find()) { ArrayList hitList = (ArrayList) mStringMap.get(currentString); @@ -108,6 +133,28 @@ public class MultipleStringLiteralsCheck extends Check } } + /** + * Analyses the path from the AST root to a given AST for occurrences + * of the token types in {@link #mIgnoreOccurrenceContext}. + * + * @param aAST the node from where to start searching towards the root node + * @return whether the path from the root node to aAST contains one of the + * token type in {@link #mIgnoreOccurrenceContext}. + */ + private boolean isInIgnoreOccurrenceContext(DetailAST aAST) + { + for (DetailAST token = aAST; + token.getParent() != null; + token = token.getParent()) + { + final int type = token.getType(); + if (mIgnoreOccurrenceContext.get(type)) { + return true; + } + } + return false; + } + /** {@inheritDoc} */ public void beginTree(DetailAST aRootAST) { diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputMultipleStringLiterals.java b/src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputMultipleStringLiterals.java index 628c70aac..7c76c55ac 100644 --- a/src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputMultipleStringLiterals.java +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputMultipleStringLiterals.java @@ -15,4 +15,16 @@ public class InputMultipleStringLiterals // The following is not reported, since it is two string literals. String a2 = "String" + "Contents"; } + + @SuppressWarnings("unchecked") + void method2(){} + + @SuppressWarnings("unchecked") + void method3(){} + + @SuppressWarnings("unchecked") + void method4(){} + + @SuppressWarnings("unchecked") + void method5(){} } diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheckTest.java index 7fbdb10c1..5ce3836c1 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheckTest.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheckTest.java @@ -56,4 +56,21 @@ public class MultipleStringLiteralsCheckTest extends BaseCheckTestCase getPath("coding" + File.separator + "InputMultipleStringLiterals.java"), expected); } + + public void testItWithoutIgnoringAnnotations() throws Exception + { + DefaultConfiguration checkConfig = + createCheckConfig(MultipleStringLiteralsCheck.class); + checkConfig.addAttribute("allowedDuplicates", "3"); + checkConfig.addAttribute("ignoreOccurrenceContext", ""); + + final String[] expected = { + "19:23: The String \"unchecked\" appears 4 times in the file.", + }; + + verify(checkConfig, + getPath("coding" + File.separator + "InputMultipleStringLiterals.java"), + expected); + } + } diff --git a/src/xdocs/config_coding.xml b/src/xdocs/config_coding.xml index c66ea14e4..524700ba5 100755 --- a/src/xdocs/config_coding.xml +++ b/src/xdocs/config_coding.xml @@ -2019,6 +2019,23 @@ case 3: regular expression ^""$ (ignore empty strings) + + ignoreOccurrenceContext + + Token type names where duplicate strings are ignored even if they don't match + ignoredStringsRegexp. This allows you to exclude syntactical contexts like + Annotations or static initializers from the check. + + + list of + token type + names + + + ANNOTATION + (ignore strings inside the context of an annotation) + + @@ -2046,6 +2063,17 @@ case 3: <module name="MultipleStringLiterals"> <property name="allowedDuplicates" value='^(("")|(", "))$'/> +</module> + + +

+ To configure the check so that it flags duplicate strings in all + syntactical contexts, even in annotations like + @SuppressWarnings("unchecked"): +

+ +<module name="MultipleStringLiterals"> + <property name="ignoreOccurrenceContext" value=""/> </module> diff --git a/src/xdocs/releasenotes.xml b/src/xdocs/releasenotes.xml index ef220ec5f..fd2ff0778 100755 --- a/src/xdocs/releasenotes.xml +++ b/src/xdocs/releasenotes.xml @@ -16,6 +16,11 @@
  • checkstyle-all.jar contained some classes from jakarta commons-collections twice. (bug 1630361)
  • +
  • + Multiple string literal check now ignores annotations by default (bug 1560940). + It is possible to retain the old behaviour by setting the new check property + ignoreOccurrenceContext to an empty value. +
  • New features: