001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2019 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;
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 the style of array type definitions.
030 * Some like Java style: {@code public static void main(String[] args)}
031 * and some like C style: {@code public static void main(String args[])}.
032 * </p>
033 * <p>
034 * By default the Check enforces Java style.
035 * </p>
036 * <p>
037 * This check strictly enforces only Java style for method return types regardless
038 * of the value for 'javaStyle'. For example, {@code byte[] getData()}.
039 * This is because C doesn't compile methods with array declarations on the name.
040 * </p>
041 * <ul>
042 * <li>
043 * Property {@code javaStyle} - Control whether to enforce Java style (true) or C style (false).
044 * Default value is {@code true}.
045 * </li>
046 * </ul>
047 * <p>
048 * To configure the check to enforce Java style:
049 * </p>
050 * <pre>
051 * &lt;module name="ArrayTypeStyle"/&gt;
052 * </pre>
053 * <p>
054 * Example:
055 * </p>
056 * <pre>
057 * public class MyClass {
058 *   int[] nums; // OK
059 *   String strings[]; // violation
060 *
061 *   char[] toCharArray() { // OK
062 *     return null;
063 *   }
064 *
065 *   byte getData()[] { // violation
066 *     return null;
067 *   }
068 * }
069 * </pre>
070 * <p>
071 * To configure the check to enforce C style:
072 * </p>
073 * <pre>
074 * &lt;module name="ArrayTypeStyle"&gt;
075 *   &lt;property name="javaStyle" value="false"/&gt;
076 * &lt;/module&gt;
077 * </pre>
078 * <p>
079 * Example:
080 * </p>
081 * <pre>
082 * public class MyClass {
083 *   int[] nums; // violation
084 *   String strings[]; // OK
085 *
086 *   char[] toCharArray() { // OK
087 *     return null;
088 *   }
089 *
090 *   byte getData()[] { // violation
091 *     return null;
092 *   }
093 * }
094 * </pre>
095 *
096 * @since 3.1
097 */
098@StatelessCheck
099public class ArrayTypeStyleCheck extends AbstractCheck {
100
101    /**
102     * A key is pointing to the warning message text in "messages.properties"
103     * file.
104     */
105    public static final String MSG_KEY = "array.type.style";
106
107    /** Control whether to enforce Java style (true) or C style (false). */
108    private boolean javaStyle = true;
109
110    @Override
111    public int[] getDefaultTokens() {
112        return getRequiredTokens();
113    }
114
115    @Override
116    public int[] getAcceptableTokens() {
117        return getRequiredTokens();
118    }
119
120    @Override
121    public int[] getRequiredTokens() {
122        return new int[] {TokenTypes.ARRAY_DECLARATOR};
123    }
124
125    @Override
126    public void visitToken(DetailAST ast) {
127        final DetailAST typeAST = ast.getParent();
128        if (typeAST.getType() == TokenTypes.TYPE) {
129            final DetailAST variableAST = typeAST.getNextSibling();
130            if (variableAST != null) {
131                final boolean isMethod = typeAST.getParent().getType() == TokenTypes.METHOD_DEF;
132                final boolean isJavaStyle = variableAST.getLineNo() > ast.getLineNo()
133                    || variableAST.getColumnNo() - ast.getColumnNo() > -1;
134
135                // force all methods to be Java style (see note in top Javadoc)
136                final boolean isMethodViolation = isMethod && !isJavaStyle;
137                final boolean isVariableViolation = !isMethod && isJavaStyle != javaStyle;
138
139                if (isMethodViolation || isVariableViolation) {
140                    log(ast, MSG_KEY);
141                }
142            }
143        }
144    }
145
146    /**
147     * Setter to control whether to enforce Java style (true) or C style (false).
148     * @param javaStyle true if Java style should be used.
149     */
150    public void setJavaStyle(boolean javaStyle) {
151        this.javaStyle = javaStyle;
152    }
153
154}