001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2026 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; 026import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 027 028/** 029 * <div> 030 * Checks that array initialization contains a trailing comma. 031 * </div> 032 * 033 * {@snippet lang="text" : 034 * int[] a = new int[] 035 * { 036 * 1, 037 * 2, 038 * 3, 039 * }; 040 * } 041 * 042 * <p> 043 * By default, the check demands a comma at the end if neither left nor right curly braces 044 * are on the same line as the last element of the array. 045 * </p> 046 * {@snippet lang="text" : 047 * return new int[] { 0 }; 048 * return new int[] { 0 049 * }; 050 * return new int[] { 051 * 0 }; 052 * } 053 * 054 * <p> 055 * Rationale: Putting this comma in makes it easier to change the 056 * order of the elements or add new elements on the end. Main benefit of a trailing 057 * comma is that when you add new entry to an array, no surrounding lines are changed. 058 * </p> 059 * {@snippet lang="text" : 060 * { 061 * 100000000000000000000, 062 * 200000000000000000000, // OK 063 * } 064 * 065 * { 066 * 100000000000000000000, 067 * 200000000000000000000, 068 * 300000000000000000000, // Just this line added, no other changes 069 * } 070 * } 071 * 072 * <p> 073 * If closing brace is on the same line as trailing comma, this benefit is gone 074 * (as the check does not demand a certain location of curly braces the following 075 * two cases will not produce a violation): 076 * </p> 077 * {@snippet lang="text" : 078 * {100000000000000000000, 079 * 200000000000000000000,} // Trailing comma not needed, line needs to be modified anyway 080 * 081 * {100000000000000000000, 082 * 200000000000000000000, // Modified line 083 * 300000000000000000000,} // Added line 084 * } 085 * 086 * <p> 087 * If opening brace is on the same line as trailing comma there's also (more arguable) problem: 088 * </p> 089 * {@snippet lang="text" : 090 * {100000000000000000000, // Line cannot be just duplicated to slightly modify entry 091 * } 092 * 093 * {100000000000000000000, 094 * 100000000000000000001, // More work needed to duplicate 095 * } 096 * } 097 * 098 * @since 3.2 099 */ 100@StatelessCheck 101public class ArrayTrailingCommaCheck extends AbstractCheck { 102 103 /** 104 * A key is pointing to the warning message text in "messages.properties" file. 105 */ 106 public static final String MSG_KEY = "array.trailing.comma"; 107 108 /** 109 * Control whether to always check for a trailing comma, even when an array is inline. 110 */ 111 private boolean alwaysDemandTrailingComma; 112 113 /** 114 * Creates a new {@code ArrayTrailingCommaCheck} instance. 115 */ 116 public ArrayTrailingCommaCheck() { 117 // no code by default 118 } 119 120 /** 121 * Setter to control whether to always check for a trailing comma, even when an array is inline. 122 * 123 * @param alwaysDemandTrailingComma whether to always check for a trailing comma. 124 * @since 8.33 125 */ 126 public void setAlwaysDemandTrailingComma(boolean alwaysDemandTrailingComma) { 127 this.alwaysDemandTrailingComma = alwaysDemandTrailingComma; 128 } 129 130 @Override 131 public int[] getDefaultTokens() { 132 return getRequiredTokens(); 133 } 134 135 @Override 136 public int[] getAcceptableTokens() { 137 return getRequiredTokens(); 138 } 139 140 @Override 141 public int[] getRequiredTokens() { 142 return new int[] {TokenTypes.ARRAY_INIT}; 143 } 144 145 @Override 146 public void visitToken(DetailAST arrayInit) { 147 final DetailAST rcurly = arrayInit.findFirstToken(TokenTypes.RCURLY); 148 final DetailAST previousSibling = rcurly.getPreviousSibling(); 149 150 if (arrayInit.getChildCount() != 1 151 && (alwaysDemandTrailingComma 152 || !TokenUtil.areOnSameLine(rcurly, previousSibling) 153 && !TokenUtil.areOnSameLine(arrayInit, previousSibling)) 154 && previousSibling.getType() != TokenTypes.COMMA) { 155 log(previousSibling, MSG_KEY); 156 } 157 } 158 159}