Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #464: Enum trailing comma check implemented #814

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ EmptyPublicCtorInClassCheck.desc = <p>This Check looks for useless empty public
EmptyPublicCtorInClassCheck.classAnnotationNames = Regex which matches names of class annotations which require class to have public no-argument ctor. Default value is "javax\\.persistence\\.Entity".
EmptyPublicCtorInClassCheck.ctorAnnotationNames = Regex which matches names of ctor annotations which make empty public ctor essential. Default value is "com\\.google\\.inject\\.Inject".

EnumTrailingComma.name = Enum Trailing Comma
EnumTrailingComma.desc = <p>The check demands a comma at the end if neither left nor right curly braces are on the same line as the last element of the enum.</p>

FinalizeImplementationCheck.name = Finalize Implementation
FinalizeImplementationCheck.desc = <p>This Check detects 3 most common cases of incorrect finalize() method implementation:</p><ul><li>negates effect of superclass finalize<br/><code>protected void finalize() { } <br/> protected void finalize() { doSomething(); }</code></li><li>useless (or worse) finalize<br/><code>protected void finalize() { super.finalize(); }</code></li><li>public finalize<br/><code>public void finalize() { try { doSomething(); } finally { super.finalize() } }</code></li></ul>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,13 @@
<message-key key="empty.public.ctor"/>
</rule-metadata>

<rule-metadata name="%EnumTrailingComma.name" internal-name="EnumTrailingComma" parent="TreeWalker">
<alternative-name internal-name="com.github.sevntu.checkstyle.checks.coding.EnumTrailingComma"/>
<description>%EnumTrailingComma.desc</description>

<message-key key="enum.trailing.comma"/>
</rule-metadata>

<rule-metadata name="%ForbidCertainImportsCheck.name" internal-name="ForbidCertainImportsCheck" parent="TreeWalker">
<alternative-name internal-name="com.github.sevntu.checkstyle.checks.coding.ForbidCertainImportsCheck"/>
<description>%ForbidCertainImportsCheck.desc</description>
Expand Down
1 change: 1 addition & 0 deletions sevntu-checks/sevntu-checks.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@
<property name="ignoreFieldNamePattern" value="serialVersionUID"/>
</module>
<module name="com.github.sevntu.checkstyle.checks.coding.EmptyPublicCtorInClassCheck"/>
<module name="com.github.sevntu.checkstyle.checks.coding.EnumTrailingComma"/>
<module name="com.github.sevntu.checkstyle.checks.coding.DiamondOperatorForVariableDefinitionCheck"/>
<module name="com.github.sevntu.checkstyle.checks.coding.NameConventionForJunit4TestClassesCheck"/>
<module name="com.github.sevntu.checkstyle.checks.coding.UselessSuperCtorCallCheck"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2020 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.github.sevntu.checkstyle.checks.coding;

import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

/**
* <p>
* Checks that enums contains a trailing comma.
* </p>
* <pre>
* enum MovieType {
* GOOD,
* BAD,
* UGLY,
* ;
* }
* </pre>
* <p>
* The check demands a comma at the end if neither left nor right curly braces are on the same line
* as the last element of the enum.
* </p>
* <pre>
* enum MovieType {GOOD, BAD, UGLY;}
* enum MovieType {GOOD, BAD, UGLY
* ;}
* enum MovieType {GOOD, BAD,
* UGLY;}
* enum MovieType {GOOD, BAD,
* UGLY; // Violation
* }
* </pre>
* <p>
* Putting this comma in makes it easier to change the order of the elements or add new elements
* at the end. Main benefit of a trailing comma is that when you add new entry to an enum, no
* surrounding lines are changed.
* </p>
* <pre>
* enum MovieType {
* GOOD,
* BAD, //OK
* }
*
* enum MovieType {
* GOOD,
* BAD,
* UGLY, // Just this line added, no other changes
* }
* </pre>
* <p>
* If closing brace is on the same line as trailing comma, this benefit is gone (as the check does
* not demand a certain location of curly braces the following two cases will not produce a
* violation):
* </p>
* <pre>
* enum MovieType {GOOD,
* BAD,} // Trailing comma not needed, line needs to be modified anyway
*
* enum MovieType {GOOD,
* BAD, // Modified line
* UGLY,} // Added line
* </pre>
*
* @author <a href="mailto:yasser.aziza@gmail.com"> Yasser Aziza </a>
*/
public class EnumTrailingComma extends AbstractCheck {

/**
* Warning message key pointing to the warning message text in "messages.properties" file.
*/
public static final String MSG_KEY = "enum.trailing.comma";

@Override
public int[] getDefaultTokens() {
return new int[] {
TokenTypes.ENUM_CONSTANT_DEF,
};
}

@Override
public int[] getAcceptableTokens() {
return getDefaultTokens();
}

@Override
public int[] getRequiredTokens() {
return getDefaultTokens();
}

@Override
public void visitToken(DetailAST ast) {
final DetailAST nextSibling = ast.getNextSibling();

if (TokenTypes.COMMA != nextSibling.getType() && isSeparateLine(ast)) {
log(ast, MSG_KEY);
}
}

/**
* Checks if the given {@link TokenTypes#ENUM_CONSTANT_DEF} element is in the same line with
* the {@link TokenTypes#LCURLY} or {@link TokenTypes#RCURLY}.
*
* @param ast the enum node
* @return {@code true} if the element is on the same line with {@link TokenTypes#LCURLY} or
* {@link TokenTypes#RCURLY}, {@code false} otherwise.
*/
private static boolean isSeparateLine(DetailAST ast) {
final DetailAST objBlock = ast.getParent();
final DetailAST leftCurly = objBlock.findFirstToken(TokenTypes.LCURLY);
final DetailAST rightCurly = objBlock.findFirstToken(TokenTypes.RCURLY);

return !areOnSameLine(leftCurly, ast)
&& !areOnSameLine(ast, rightCurly);
}

/**
* Determines if two ASTs are on the same line.
*
* @param ast1 the first AST
* @param ast2 the second AST
*
* @return true if they are on the same line.
*/
private static boolean areOnSameLine(DetailAST ast1, DetailAST ast2) {
return ast1.getLineNo() == ast2.getLineNo();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ private enum NullnessAnnotation {
PARAMETERS_ARE_NULLABLE_BY_DEFAULT("ParametersAreNullableByDefault", PKG_JAVAX_ANNOTATION),
/** ReturnValuesAreNonnullByDefault. */
RETURN_VALUES_ARE_NONNULL_BY_DEFAULT("ReturnValuesAreNonnullByDefault",
"edu.umd.cs.findbugs.annotations");
"edu.umd.cs.findbugs.annotations"),
;

/** The annotation's name. */
private final String annotationName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ protected enum NumericType {
/**
* Denotes a binary literal. For example, 0b0011
*/
BINARY
BINARY,

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ custom.declaration.order.method=Method definition in wrong order. Expected ''{0}
diamond.operator.for.variable.definition=Diamond operator expected.
either.log.or.throw=Either log or throw exception.
empty.public.ctor=This empty public constructor is useless.
enum.trailing.comma=Enum should contain trailing comma.
finalize.implementation.missed.super.finalize=You have to call super.finalize() right after finally opening brace.
finalize.implementation.missed.try.finally=finalize() method should contain try-finally block with super.finalize() call inside finally block.
finalize.implementation.public=finalize() method should have a "protected" visibility.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2020 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.github.sevntu.checkstyle.checks.coding;

import static com.github.sevntu.checkstyle.checks.coding.EnumTrailingComma.MSG_KEY;

import org.junit.Test;

import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;

/**
* @author <a href="mailto:yasser.aziza@gmail.com"> Yasser Aziza </a>
*/
public class EnumTrailingCommaTest extends AbstractModuleTestSupport {

/**
* An error message for current check.
*/
private final String warningMessage = getCheckMessage(MSG_KEY);

@Override
protected String getPackageLocation() {
return "com/github/sevntu/checkstyle/checks/coding";
}

@Test
public void testDefault() throws Exception {
final DefaultConfiguration checkConfig = createModuleConfig(EnumTrailingComma.class);

final String[] expected = {
"14:9: " + warningMessage,
"19:9: " + warningMessage,
"27:9: " + warningMessage,
"39:9: " + warningMessage,
};

verify(checkConfig, getPath("InputEnumTrailingCommaCheck.java"), expected);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.sevntu.checkstyle.checks.coding;

public class InputEnumTrailingCommaCheck {

enum MovieType {
GOOD,
BAD,
UGLY,
;
}

enum Gender {
FEMALE,
MALE // Violation
}

enum Language {
ENGLISH,
GERMAN // Violation
;
}

// Violation
enum ErrorMessage {
USER_DOES_NOT_EXIST,
INVALID_USER_PASS,
EVERYTHING_ELSE; // Violation
}

enum BinType {ZERO, ONE
;}

enum SameLine {FIRST, SECOND, THIRD;}

enum LineBreak {FIRST, SECOND,
THIRD;}

enum LastLineBreak {FIRST, SECOND,
THIRD; // Violation
}

enum LastBreakSemicolon {FIRST, SECOND, THIRD
;
}

enum RgbColor {
RED,
GREEN,
BLUE
,
}

enum OperatingSystem {
LINUX,
MAC
,}

enum EMPTY {E
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,14 @@
</param>
</rule>

<rule>
<key>com.github.sevntu.checkstyle.checks.coding.EnumTrailingComma</key>
<name>Enum Trailing Comma</name>
<tag>coding</tag>
<description>This check ensures that enums contains a trailing comma.</description>
<configKey>Checker/TreeWalker/com.github.sevntu.checkstyle.checks.coding.EnumTrailingComma</configKey>
</rule>

<rule>
<key>com.github.sevntu.checkstyle.checks.coding.FinalizeImplementationCheck</key>
<name>Finalize Implementation Check</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void testAllRulesValid() {
Assert.assertEquals("Incorrect repository language", "java", repository.language());

final List<RulesDefinition.Rule> rules = repository.rules();
Assert.assertEquals("Incorrect number of loaded rules", 59, rules.size());
Assert.assertEquals("Incorrect number of loaded rules", 60, rules.size());

for (RulesDefinition.Rule rule : rules) {
Assert.assertNotNull("Rule key is not set", rule.key());
Expand Down