diff options
author | Sagar <sagar.shah@evivehealth.com> | 2017-03-23 01:26:03 +0530 |
---|---|---|
committer | Roman Ivanov <romani@users.noreply.github.com> | 2017-04-12 12:35:30 -0700 |
commit | 73e8b213fff84af542329e99d76606b47bb14c5d (patch) | |
tree | 567ae774d6b036d92d21912fc56ee5ac6302a34b /src | |
parent | 739ec9427d4cb94962daf7a88402e9ca07b6094e (diff) | |
download | checkstyle-73e8b213fff84af542329e99d76606b47bb14c5d.tar.gz |
Issue #4078: DefaultComesLast only if doesnt share case
Diffstat (limited to 'src')
14 files changed, 363 insertions, 11 deletions
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java index 673687bc4..5d0da6d4d 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java @@ -19,6 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.Objects; + import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -49,6 +51,16 @@ public class DefaultComesLastCheck extends AbstractCheck { */ public static final String MSG_KEY = "default.comes.last"; + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE = + "default.comes.last.in.casegroup"; + + /** Whether to process skipIfLastAndSharedWithCaseInSwitch() invocations. */ + private boolean skipIfLastAndSharedWithCase; + @Override public int[] getAcceptableTokens() { return new int[] { @@ -66,6 +78,14 @@ public class DefaultComesLastCheck extends AbstractCheck { return getAcceptableTokens(); } + /** + * Whether to allow default keyword not in last but surrounded with case. + * @param newValue whether to ignore checking. + */ + public void setSkipIfLastAndSharedWithCase(boolean newValue) { + skipIfLastAndSharedWithCase = newValue; + } + @Override public void visitToken(DetailAST ast) { final DetailAST defaultGroupAST = ast.getParent(); @@ -73,15 +93,41 @@ public class DefaultComesLastCheck extends AbstractCheck { //interested in if (defaultGroupAST.getType() != TokenTypes.ANNOTATION_FIELD_DEF && defaultGroupAST.getType() != TokenTypes.MODIFIERS) { - final DetailAST switchAST = defaultGroupAST.getParent(); - final DetailAST lastGroupAST = - switchAST.getLastChild().getPreviousSibling(); - if (defaultGroupAST.getLineNo() != lastGroupAST.getLineNo() - || defaultGroupAST.getColumnNo() - != lastGroupAST.getColumnNo()) { + if (skipIfLastAndSharedWithCase) { + if (Objects.nonNull(findNextSibling(ast, TokenTypes.LITERAL_CASE))) { + log(ast, MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE); + } + else if (ast.getPreviousSibling() == null + && Objects.nonNull(findNextSibling(defaultGroupAST, + TokenTypes.CASE_GROUP))) { + log(ast, MSG_KEY); + } + } + else if (Objects.nonNull(findNextSibling(defaultGroupAST, + TokenTypes.CASE_GROUP))) { log(ast, MSG_KEY); } } } + + /** + * Return token type only if passed tokenType in argument is found or returns -1. + * + * @param ast root node. + * @param tokenType tokentype to be processed. + * @return token if desired token is found or else null. + */ + private static DetailAST findNextSibling(DetailAST ast, int tokenType) { + DetailAST token = null; + DetailAST node = ast.getNextSibling(); + while (node != null) { + if (node.getType() == tokenType) { + token = node; + break; + } + node = node.getNextSibling(); + } + return token; + } } diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties index 29494b5ef..2fadac51b 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties @@ -8,6 +8,7 @@ declaration.order.static=Static variable definition in wrong order. declaration.order.instance=Instance variable definition in wrong order. declaration.order.access=Variable access definition in wrong order. default.comes.last=Default should be last label in the switch. +default.comes.last.in.casegroup=Default should be last label in the case group. empty.statement=Empty statement. equals.avoid.null=String literal expressions should be on the left side of an equals comparison. equalsIgnoreCase.avoid.null=String literal expressions should be on the left side of an equalsIgnoreCase comparison. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties index 6a101f008..59ce1befb 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties @@ -8,6 +8,7 @@ declaration.order.static=Die statische Variable wird an der falschen Stelle dekl declaration.order.instance=Die Instanz-Variable wird an der falschen Stelle deklariert. declaration.order.access=Fehlerhafte Deklarationsreihenfolge für diesen Scope. default.comes.last=Der Default-Fall sollte der letzte Fall der switch-Anweisung sein. +default.comes.last.in.casegroup=Default sollte letztes Label in der Fallgruppe sein. empty.statement=Leere Anweisung. equals.avoid.null=Bei einem equals()-Vergleich sollten String-Literale auf der linken Seite stehen. equalsIgnoreCase.avoid.null=Bei einem equalsIgnoreCase()-Vergleich sollten String-Literale auf der linken Seite stehen. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties index 09622029e..64817403c 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties @@ -55,6 +55,7 @@ modified.control.variable=Se modifica la variable de control ''{0}''. explicit.init=La variable ''{0}'' se inicializa explicitamente a ''{1}'' (valor por defecto para su tipo). default.comes.last=La etiqueta default debe ser la última etiqueta en el switch. +default.comes.last.in.casegroup=El valor predeterminado debe ser la última etiqueta en el grupo de casos. missing.ctor=La clase debería definir un constructor. fall.through=Caída desde la etiqueta anterior en la sentencia switch. require.this.variable=La referencia a la variable de instancia ''{0}'' necesita \"{1}this.\". diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties index 29064147f..69e0639fb 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties @@ -28,6 +28,7 @@ declaration.order.static = Staattinen muuttuja määritelmä väärässä järje declaration.order.instance = Esimerkiksi muuttuja määritelmä väärässä järjestyksessä. declaration.order.access = Muuttuja pääsy määritelmä väärässä järjestyksessä. default.comes.last = Oletus pitäisi olla viimeinen tarra kytkin. +default.comes.last.in.casegroup=Oletus on oltava viimeinen tarra tapauksessa ryhmässä. empty.statement = Tyhjä lausunto. equals.avoid.null = String kirjaimellinen ilmaisuja pitäisi olla vasemmalla puolella vastaa vertailun. equalsIgnoreCase.avoid.null = String kirjaimellinen ilmaisuja pitäisi olla vasemmalla puolella equalsIgnoreCase vertailun. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties index 673424434..d7b2da563 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties @@ -56,6 +56,7 @@ modified.control.variable=La variable de contrôle ''{0}'' est modifiée. explicit.init=L''initialisation explicite de la variable ''{0}'' à la valeur ''{1}'' est inutile, c''est la valeur par défaut pour ce type. default.comes.last=Le cas \"default\" devrait apparaitre en dernier dans le bloc \"switch\". +default.comes.last.in.casegroup=La valeur par défaut doit être la dernière étiquette dans le groupe de cas. missing.ctor=Il manque un constructeur à la classe. fall.through=Le cas précédent du \"switch\" ne contient pas de break, return, throw ou continue. fall.through.last=Le dernier cas du \"switch\" ne contient pas de break, return, throw ou continue. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties index fe5907fa5..c4bfcf3ea 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties @@ -52,6 +52,7 @@ explicit.init=変数 ''{0}'' が明示的に ''{1}'' (この型のデフォル avoid.finalizer.method = ファイナライザメソッドを使用しないでください。 avoid.clone.method = cloneメソッドを使用しないでください。 default.comes.last = default は switch 文の最後のラベルにしてください。 +default.comes.last.in.casegroup=デフォルトは、ケースグループの最後のラベルにする必要があります。 equals.avoid.null = equals による比較では、文字列リテラル式を左側にしてください。 equalsIgnoreCase.avoid.null = equals による比較では、文字列リテラル式を左側にしてください。 fall.through = switch 文の前の分岐からフォールスルーしています。 diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties index 11a1e2456..5d4348b29 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties @@ -32,6 +32,7 @@ string.literal.equality=\"Strings\" literais devem ser comparadas com equals(), avoid.finalizer.method = Evite o uso de método finalizador. avoid.clone.method = Evite o uso de método clone. default.comes.last = Padrão deve ser a última etiqueta no interruptor. +default.comes.last.in.casegroup=O padrão deve ser o último marcador no grupo de casos. equals.avoid.null = Corda expressões literais deve estar no lado esquerdo de um é igual comparação. equalsIgnoreCase.avoid.null = Corda expressões literais deve estar no lado esquerdo de uma comparação equalsIgnoreCase. fall.through = Queda através do ramo anterior da instrução switch. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties index 4e4bd1de7..1dc5430a5 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties @@ -15,6 +15,7 @@ declaration.order.instance = Değişken tanımı yanlış sırada yapılmış declaration.order.static = ''static'' değişken tanımı yanlış sırada yapılmış. default.comes.last = ''switch'' içerisindeki ''default'' ifadesi son durum olarak yer almalıdır. +default.comes.last.in.casegroup=Varsayılan değer, vaka grubundaki son etiket olmalıdır. empty.statement = Boş ifade. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties index 10089b732..042c3bdc5 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties @@ -8,6 +8,7 @@ declaration.order.static=静态属性定义顺序错误。 declaration.order.instance=实例属性定义顺序错误。 declaration.order.access=属性访问器定义顺序错误。 default.comes.last=default 应为 switch 块最后一个元素。 +default.comes.last.in.casegroup=默认值应为案例组中的最后一个标签。 empty.statement=避免空行。 equals.avoid.null=字符串常量应出现在 equals 比较的左侧。 equalsIgnoreCase.avoid.null=字符串常量应出现在 equalsIgnoreCase 比较的左侧。 diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheckTest.java index 467263bd1..60dc75513 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheckTest.java @@ -20,6 +20,7 @@ package com.puppycrawl.tools.checkstyle.checks.coding; import static com.puppycrawl.tools.checkstyle.checks.coding.DefaultComesLastCheck.MSG_KEY; +import static com.puppycrawl.tools.checkstyle.checks.coding.DefaultComesLastCheck.MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE; import java.io.File; import java.io.IOException; @@ -32,6 +33,9 @@ import com.puppycrawl.tools.checkstyle.DefaultConfiguration; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; public class DefaultComesLastCheckTest extends BaseCheckTestSupport { + + private DefaultConfiguration checkConfig; + @Override protected String getPath(String filename) throws IOException { return super.getPath("checks" + File.separator @@ -45,12 +49,41 @@ public class DefaultComesLastCheckTest extends BaseCheckTestSupport { } @Test + public void testSkipIfLastAndSharedWithCase() throws Exception { + checkConfig = createCheckConfig(DefaultComesLastCheck.class); + checkConfig.addAttribute("skipIfLastAndSharedWithCase", "true"); + final String[] expected = { + "17:13: " + getCheckMessage(MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE), + "25:13: " + getCheckMessage(MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE), + "33:21: " + getCheckMessage(MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE), + "37:13: " + getCheckMessage(MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE), + "57:13: " + getCheckMessage(MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE), + "77:13: " + getCheckMessage(MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE), + "89:13: " + getCheckMessage(MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE), + "98:13: " + getCheckMessage(MSG_KEY), + }; + + verify(checkConfig, getPath("InputSkipIfLastAndSharedWithCase.java"), expected); + } + + @Test public void testDefault() throws Exception { - final DefaultConfiguration checkConfig = - createCheckConfig(DefaultComesLastCheck.class); + checkConfig = createCheckConfig(DefaultComesLastCheck.class); final String[] expected = { "25:9: " + getCheckMessage(MSG_KEY), "32:24: " + getCheckMessage(MSG_KEY), + "37:13: " + getCheckMessage(MSG_KEY), + "45:13: " + getCheckMessage(MSG_KEY), + "53:13: " + getCheckMessage(MSG_KEY), + "61:21: " + getCheckMessage(MSG_KEY), + "65:13: " + getCheckMessage(MSG_KEY), + "69:21: " + getCheckMessage(MSG_KEY), + "74:13: " + getCheckMessage(MSG_KEY), + "85:13: " + getCheckMessage(MSG_KEY), + "96:13: " + getCheckMessage(MSG_KEY), + "106:13: " + getCheckMessage(MSG_KEY), + "114:13: " + getCheckMessage(MSG_KEY), + "125:13: " + getCheckMessage(MSG_KEY), }; verify(checkConfig, getPath("InputDefaultComesLast.java"), @@ -60,8 +93,7 @@ public class DefaultComesLastCheckTest extends BaseCheckTestSupport { @Test public void testDefaultMethodsInJava8() throws Exception { - final DefaultConfiguration checkConfig = - createCheckConfig(DefaultComesLastCheck.class); + checkConfig = createCheckConfig(DefaultComesLastCheck.class); final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputDefaultComesLastDefaultMethodsInInterface.java"), diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/defaultcomeslast/InputDefaultComesLast.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/defaultcomeslast/InputDefaultComesLast.java index 08a08d1f7..a61f2adae 100644 --- a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/defaultcomeslast/InputDefaultComesLast.java +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/defaultcomeslast/InputDefaultComesLast.java @@ -31,6 +31,104 @@ public class InputDefaultComesLast switch (i) { case 1: break; default: break; case 2: break; } + + switch (i) { + case 1: + default: //violation + break; + case 2: + break; + } + + switch (i) { + case 1: + default: //violation + case 2: + break; + case 3: + break; + } + + switch (i) { + default: //violation + case 1: + break; + case 2: + break; + } + + switch (i) { + case 0: default: case 1: break; case 2: break; //violation + } + + switch (i) { + default: case 1: break; case 2: break; //violation + } + + switch (i) { + case 1: default: break; case 2: break; //violation + } + + switch (i) { + case 1: + default: //violation + break; + case 2: + break; + case 3: + break; + } + + switch (i) { + case 1: + break; + default: //violation + case 2: + break; + case 3: + break; + } + + switch (i) { + case 1: + break; + case 2: + default: //violation + break; + case 3: + break; + } + + switch (i) { + case 1: + break; + case 2: + default: //violation + case 3: + break; + case 4: + break; + } + + switch (i) { + default: //violation + break; + case 1: + break; + } + + switch (i) { + case 1: + break; + case 2: + break; + default: //violation + case 5: + case 6: + break; + case 7: + break; + } } } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/defaultcomeslast/InputSkipIfLastAndSharedWithCase.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/defaultcomeslast/InputSkipIfLastAndSharedWithCase.java new file mode 100644 index 000000000..aa9435b6e --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/defaultcomeslast/InputSkipIfLastAndSharedWithCase.java @@ -0,0 +1,119 @@ +package com.puppycrawl.tools.checkstyle.checks.coding.defaultcomeslast; + + +public class InputSkipIfLastAndSharedWithCase +{ + void method(int i) { + switch (i) { + case 1: + default: // No violation with the new option is expected + break; + case 2: + break; + } + + switch (i) { + case 1: + default: // violation Default should be last label in the case group. + case 2: + break; + case 3: + break; + } + + switch (i) { + default: // violation Default should be last label in the case group. + case 1: + break; + case 2: + break; + } + + switch (i) { + case 0: default: case 1: break; case 2: break; // violation Default should be last label in the case group. + } + + switch (i) { + default: case 1: break; case 2: break; // violation Default should be last label in the case group. + } + + switch (i) { + case 1: default: break; case 2: break; // No violation with the new option is expected + } + + switch (i) { + case 1: + default: // No violation with the new option is expected + break; + case 2: + break; + case 3: + break; + } + + switch (i) { + case 1: + break; + default: // violation Default should be last label in the case group. + case 2: + break; + case 3: + break; + } + + switch (i) { + case 1: + break; + case 2: + default: // No violation with the new option is expected + break; + case 3: + break; + } + + switch (i) { + case 1: + break; + default: // violation Default should be last label in the case group. + case 3: + break; + case 4: + break; + } + + switch (i) { + case 1: + break; + case 2: + break; + default: // violation Default should be last label in the group. + case 5: + case 6: + break; + } + + switch (i) { + case 1: + break; + default: // violation Default should be last label in the case group. + break; + case 2: + break; + } + + switch (i) { + case 1: + break; + case 2: + break; + default: // No violation. + break; + } + + } +} + +@interface InputSkipIfLastAndSharedWithCaseAnnotation +{ + int blag() default 1; +} diff --git a/src/xdocs/config_coding.xml b/src/xdocs/config_coding.xml index 6f89b72af..91e2aaddf 100644 --- a/src/xdocs/config_coding.xml +++ b/src/xdocs/config_coding.xml @@ -464,7 +464,22 @@ public class A { more readable if it comes after the last <code>case</code>. </p> </subsection> - + <subsection name="Properties"> + <table> + <tr> + <th>name</th> + <th>description</th> + <th>type</th> + <th>default value</th> + </tr> + <tr> + <td>skipIfLastAndSharedWithCase</td> + <td>whether to allow <code>default</code> along with case if they are not last</td> + <td><a href="property_types.html#boolean">Boolean</a></td> + <td>false</td> + </tr> + </table> + </subsection> <subsection name="Examples"> <p> To configure the check: @@ -472,6 +487,35 @@ public class A { <source> <module name="DefaultComesLast"/> </source> + <p> + To configure the check for skipIfLastAndSharedWithCase: + </p> + <source> +<module name="DefaultComesLast"> + <property name="skipIfLastAndSharedWithCase" value="true"/> +</module> + </source> + <p> + Example when skipIfLastAndSharedWithCase is set to true. + </p> + <source> +switch (i) { + case 1: + break; + case 2: + default: // No violation with the new option is expected + break; + case 3: + break; +} +switch (i) { + case 1: + break; + default: // violation with the new option is expected + case 2: + break; +} + </source> </subsection> <subsection name="Example of Usage"> @@ -489,6 +533,10 @@ public class A { <a href="https://github.com/search?q=path%3Asrc%2Fmain%2Fresources%2Fcom%2Fpuppycrawl%2Ftools%2Fcheckstyle%2Fchecks%2Fcoding+filename%3Amessages*.properties+repo%3Acheckstyle%2Fcheckstyle+%22default.comes.last%22"> default.comes.last</a> </li> + <li> + <a href="https://github.com/search?q=path%3Asrc%2Fmain%2Fresources%2Fcom%2Fpuppycrawl%2Ftools%2Fcheckstyle%2Fchecks%2Fcoding+filename%3Amessages*.properties+repo%3Acheckstyle%2Fcheckstyle+%22default.comes.last.in.casegroup%22"> + default.comes.last.in.casegroup</a> + </li> </ul> <p> All messages can be customized if the default message doesn't suit you. |