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 array initialization contains a trailing comma. 030 * </p> 031 * <pre> 032 * int[] a = new int[] 033 * { 034 * 1, 035 * 2, 036 * 3, 037 * }; 038 * </pre> 039 * <p> 040 * The check demands a comma at the end if neither left nor right curly braces 041 * are on the same line as the last element of the array. 042 * </p> 043 * <pre> 044 * return new int[] { 0 }; 045 * return new int[] { 0 046 * }; 047 * return new int[] { 048 * 0 }; 049 * </pre> 050 * <p> 051 * Rationale: Putting this comma in makes it easier to change the 052 * order of the elements or add new elements on the end. Main benefit of a trailing 053 * comma is that when you add new entry to an array, no surrounding lines are changed. 054 * </p> 055 * <pre> 056 * { 057 * 100000000000000000000, 058 * 200000000000000000000, // OK 059 * } 060 * 061 * { 062 * 100000000000000000000, 063 * 200000000000000000000, 064 * 300000000000000000000, // Just this line added, no other changes 065 * } 066 * </pre> 067 * <p> 068 * If closing brace is on the same line as training comma, this benefit is gone 069 * (as the check does not demand a certain location of curly braces the following 070 * two cases will not produce a violation): 071 * </p> 072 * <pre> 073 * {100000000000000000000, 074 * 200000000000000000000,} // Trailing comma not needed, line needs to be modified anyway 075 * 076 * {100000000000000000000, 077 * 200000000000000000000, // Modified line 078 * 300000000000000000000,} // Added line 079 * </pre> 080 * <p> 081 * If opening brace is on the same line as training comma there's also (more arguable) problem: 082 * </p> 083 * <pre> 084 * {100000000000000000000, // Line cannot be just duplicated to slightly modify entry 085 * } 086 * 087 * {100000000000000000000, 088 * 100000000000000000001, // More work needed to duplicate 089 * } 090 * </pre> 091 * <p> 092 * To configure the check: 093 * </p> 094 * <pre> 095 * <module name="ArrayTrailingComma"/> 096 * </pre> 097 * <p> 098 * Which results in the following violations: 099 * </p> 100 * <pre> 101 * int[] numbers = {1, 2, 3}; //no violation 102 * boolean[] bools = { 103 * true, 104 * true, 105 * false 106 * }; //violation 107 * 108 * String[][] text = {{},{},}; //no violation 109 * 110 * double[][] decimals = { 111 * {0.5, 2.3, 1.1,}, //no violation 112 * {1.7, 1.9, 0.6}, 113 * {0.8, 7.4, 6.5} 114 * }; // violation as previous line misses a comma 115 * 116 * char[] chars = {'a', 'b', 'c' 117 * }; / /no violation 118 * 119 * String[] letters = { 120 * "a", "b", "c"}; // no violation 121 * 122 * int[] a1 = new int[]{ 123 * 1, 124 * 2 125 * , 126 * }; // no violation 127 * 128 * int[] a2 = new int[]{ 129 * 1, 130 * 2 131 * ,}; // no violation 132 * </pre> 133 * 134 * @since 3.2 135 */ 136@StatelessCheck 137public class ArrayTrailingCommaCheck extends AbstractCheck { 138 139 /** 140 * A key is pointing to the warning message text in "messages.properties" 141 * file. 142 */ 143 public static final String MSG_KEY = "array.trailing.comma"; 144 145 @Override 146 public int[] getDefaultTokens() { 147 return getRequiredTokens(); 148 } 149 150 @Override 151 public int[] getAcceptableTokens() { 152 return getRequiredTokens(); 153 } 154 155 @Override 156 public int[] getRequiredTokens() { 157 return new int[] {TokenTypes.ARRAY_INIT}; 158 } 159 160 @Override 161 public void visitToken(DetailAST arrayInit) { 162 final DetailAST rcurly = arrayInit.findFirstToken(TokenTypes.RCURLY); 163 final DetailAST previousSibling = rcurly.getPreviousSibling(); 164 165 if (arrayInit.getChildCount() != 1 166 && rcurly.getLineNo() != previousSibling.getLineNo() 167 && arrayInit.getLineNo() != previousSibling.getLineNo() 168 && previousSibling.getType() != TokenTypes.COMMA) { 169 log(rcurly.getLineNo(), MSG_KEY); 170 } 171 } 172 173}