001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2020 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.checks.coding;
021
022import com.puppycrawl.tools.checkstyle.StatelessCheck;
023import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
024import com.puppycrawl.tools.checkstyle.api.DetailAST;
025import com.puppycrawl.tools.checkstyle.api.TokenTypes;
026
027/**
028 * <p>
029 *  Checks that enum definition does not contain a trailing comma.
030 *  Rationale: JLS allows trailing commas in arrays and enumerations, but does not allow
031 *  them in other locations. To unify the coding style, the use of trailing commas should
032 *  be prohibited.
033 * </p>
034 * <pre>
035 * enum Foo1 {
036 *   FOO,
037 *   BAR;
038 * }
039 * </pre>
040 * <p>
041 *  The check demands that there should not be any comma after last constant in
042 *  enum definition.
043 * </p>
044 * <pre>
045 * enum Foo1 {
046 *   FOO,
047 *   BAR, //violation
048 * }
049 * </pre>
050 * <p>
051 * To configure the check:
052 * </p>
053 * <pre>
054 * &lt;module name=&quot;NoEnumTrailingComma&quot;/&gt;
055 * </pre>
056 * <p>
057 * Which results in the following violations:
058 * </p>
059 * <pre>
060 * enum Foo1 {
061 *   FOO,
062 *   BAR; //OK
063 * }
064 * enum Foo2 {
065 *   FOO,
066 *   BAR //OK
067 * }
068 * enum Foo3 {
069 *   FOO,
070 *   BAR, //violation
071 * }
072 * enum Foo4 {
073 *   FOO,
074 *   BAR, // violation
075 *   ;
076 * }
077 * enum Foo5 {
078 *   FOO,
079 *   BAR,; // violation
080 * }
081 * enum Foo6 { FOO, BAR,; } // violation
082 * enum Foo7 { FOO, BAR, } // violation
083 * enum Foo8 {
084 *   FOO,
085 *   BAR // OK
086 *   ;
087 * }
088 * enum Foo9 { FOO, BAR; } // OK
089 * enum Foo10 { FOO, BAR } // OK
090 * </pre>
091 *
092 * @since 8.29
093 */
094@StatelessCheck
095public class NoEnumTrailingCommaCheck extends AbstractCheck {
096
097    /**
098     * A key is pointing to the warning message text in "messages.properties"
099     * file.
100     */
101    public static final String MSG_KEY = "no.enum.trailing.comma";
102
103    @Override
104    public int[] getDefaultTokens() {
105        return getRequiredTokens();
106    }
107
108    @Override
109    public int[] getAcceptableTokens() {
110        return getRequiredTokens();
111    }
112
113    @Override
114    public int[] getRequiredTokens() {
115        return new int[] {TokenTypes.ENUM_CONSTANT_DEF};
116    }
117
118    @Override
119    public void visitToken(DetailAST detailAST) {
120        final DetailAST nextSibling = detailAST.getNextSibling();
121        if (nextSibling.getType() == TokenTypes.COMMA) {
122            final DetailAST nextToNextSibling = nextSibling.getNextSibling();
123            if (nextToNextSibling.getType() != TokenTypes.ENUM_CONSTANT_DEF) {
124                log(nextSibling, MSG_KEY);
125            }
126        }
127    }
128}