001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2017 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.api.AbstractCheck; 023import com.puppycrawl.tools.checkstyle.api.DetailAST; 024import com.puppycrawl.tools.checkstyle.api.TokenTypes; 025 026/** 027 * <p> 028 * Checks if array initialization contains optional trailing comma. 029 * </p> 030 * <p> 031 * Rationale: Putting this comma in make is easier to change the 032 * order of the elements or add new elements on the end. Main benefit of a trailing 033 * comma is that when you add new entry to an array, no surrounding lines are changed. 034 * </p> 035 * <p> 036 * The check demands a comma at the end if neither left nor right curly braces 037 * are on the same line as the last element of the array. 038 * </p> 039 * <pre> 040 * return new int[] { 0 }; 041 * return new int[] { 0 042 * }; 043 * return new int[] { 044 * 0 }; 045 * </pre> 046 * <pre> 047 * { 048 * 100000000000000000000, 049 * 200000000000000000000, // OK 050 * } 051 * 052 * { 053 * 100000000000000000000, 054 * 200000000000000000000, 055 * 300000000000000000000, // Just this line added, no other changes 056 * } 057 * </pre> 058 * <p> 059 * If closing brace is on the same line as training comma, this benefit is gone 060 * (as the Check does not demand a certain location of curly braces the following 061 * two cases will not produce a violation): 062 * </p> 063 * <pre> 064 * {100000000000000000000, 065 * 200000000000000000000,} // Trailing comma not needed, line needs to be modified anyway 066 * 067 * {100000000000000000000, 068 * 200000000000000000000, // Modified line 069 * 300000000000000000000,} // Added line 070 * </pre> 071 * <p> 072 * If opening brace is on the same line as training comma there's also (more arguable) problem: 073 * </p> 074 * <pre> 075 * {100000000000000000000, // Line cannot be just duplicated to slightly modify entry 076 * } 077 * 078 * {100000000000000000000, 079 * 100000000000000000001, // More work needed to duplicate 080 * } 081 * </pre> 082 * <p> 083 * An example of how to configure the check is: 084 * </p> 085 * <pre> 086 * <module name="ArrayTrailingComma"/> 087 * </pre> 088 * @author o_sukhodolsky 089 */ 090public class ArrayTrailingCommaCheck extends AbstractCheck { 091 092 /** 093 * A key is pointing to the warning message text in "messages.properties" 094 * file. 095 */ 096 public static final String MSG_KEY = "array.trailing.comma"; 097 098 @Override 099 public int[] getDefaultTokens() { 100 return getAcceptableTokens(); 101 } 102 103 @Override 104 public int[] getAcceptableTokens() { 105 return new int[] {TokenTypes.ARRAY_INIT}; 106 } 107 108 @Override 109 public int[] getRequiredTokens() { 110 return getAcceptableTokens(); 111 } 112 113 @Override 114 public void visitToken(DetailAST arrayInit) { 115 final DetailAST rcurly = arrayInit.findFirstToken(TokenTypes.RCURLY); 116 final DetailAST previousSibling = rcurly.getPreviousSibling(); 117 118 if (arrayInit.getLineNo() != rcurly.getLineNo() 119 && arrayInit.getChildCount() != 1 120 && rcurly.getLineNo() != previousSibling.getLineNo() 121 && arrayInit.getLineNo() != previousSibling.getLineNo() 122 && previousSibling.getType() != TokenTypes.COMMA) { 123 log(rcurly.getLineNo(), MSG_KEY); 124 } 125 } 126}