code: ///////////////////////////////////////////////////////////////////////////////////////////////
  // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
  // Copyright (C) 2001-2023 the original author or authors.
  //
  // This library is free software; you can redistribute it and/or
  // modify it under the terms of the GNU Lesser General Public
  // License as published by the Free Software Foundation; either
  // version 2.1 of the License, or (at your option) any later version.
  //
  // This library is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  // Lesser General Public License for more details.
  //
  // You should have received a copy of the GNU Lesser General Public
  // License along with this library; if not, write to the Free Software
  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  ///////////////////////////////////////////////////////////////////////////////////////////////
  
  package com.puppycrawl.tools.checkstyle.checks.coding;
  
  import com.puppycrawl.tools.checkstyle.StatelessCheck;
  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
  import com.puppycrawl.tools.checkstyle.api.DetailAST;
  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
  import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
  
  /**
   * <p>
   * Checks that array initialization contains a trailing comma.
   * </p>
   * <pre>
   * int[] a = new int[]
   * {
   *   1,
   *   2,
   *   3,
   * };
   * </pre>
   * <p>
   * By default, the check demands a comma at the end if neither left nor right curly braces
   * are on the same line as the last element of the array.
   * </p>
   * <pre>
   * return new int[] { 0 };
   * return new int[] { 0
   *   };
   * return new int[] {
   *   0 };
   * </pre>
   * <p>
   * Rationale: Putting this comma in makes it easier to change the
   * order of the elements or add new elements on the end. Main benefit of a trailing
   * comma is that when you add new entry to an array, no surrounding lines are changed.
   * </p>
   * <pre>
   * {
   *   100000000000000000000,
   *   200000000000000000000, // OK
   * }
   *
   * {
   *   100000000000000000000,
   *   200000000000000000000,
   *   300000000000000000000,  // Just this line added, no other changes
   * }
   * </pre>
   * <p>
   * If closing brace is on the same line as trailing comma, this benefit is gone
   * (as the check does not demand a certain location of curly braces the following
   * two cases will not produce a violation):
   * </p>
   * <pre>
   * {100000000000000000000,
   *  200000000000000000000,} // Trailing comma not needed, line needs to be modified anyway
   *
   * {100000000000000000000,
   *  200000000000000000000, // Modified line
   *  300000000000000000000,} // Added line
   * </pre>
   * <p>
   * If opening brace is on the same line as trailing comma there's also (more arguable) problem:
   * </p>
   * <pre>
   * {100000000000000000000, // Line cannot be just duplicated to slightly modify entry
   * }
   *
   * {100000000000000000000,
   *  100000000000000000001, // More work needed to duplicate
   * }
   * </pre>
   * <ul>
   * <li>
   * Property {@code alwaysDemandTrailingComma} - Control whether to always check for a trailing
   * comma, even when an array is inline.
   * Type is {@code boolean}.
   * Default value is {@code false}.
   * </li>
   * </ul>
   * <p>
   * To configure the check:
   * </p>
   * <pre>
   * &lt;module name=&quot;ArrayTrailingComma&quot;/&gt;
   * </pre>
   * <p>
   * Which results in the following violations:
   * </p>
   * <pre>
   * int[] numbers = {1, 2, 3};        //no violation
   * boolean[] bools = {
   * true,
   * true,
   * false
   * };        //violation
   *
   * String[][] text = {{},{},};        //no violation
   *
   * double[][] decimals = {
   * {0.5, 2.3, 1.1,},        //no violation
   * {1.7, 1.9, 0.6},
   * {0.8, 7.4, 6.5}
   * };        // violation as previous line misses a comma
   *
   * char[] chars = {'a', 'b', 'c'
   *   };        / /no violation
   *
   * String[] letters = {
   *   "a", "b", "c"};        // no violation
   *
   * int[] a1 = new int[]{
   *   1,
   *   2
   *   ,
   * };        // no violation
   *
   * int[] a2 = new int[]{
   *   1,
   *   2
   *   ,};        // no violation
   * </pre>
   *
   * <p>To configure check to always validate trailing comma:</p>
   * <pre>
   * &lt;module name="ArrayTrailingComma"&gt;
   *   &lt;property name="alwaysDemandTrailingComma" value="true"/&gt;
   * &lt;/module&gt;
   * </pre>
   * <p>Example:</p>
   * <pre>
   * int[] numbers = {1, 2, 3}; // violation
   * boolean[] bools = {
   * true,
   * true,
   * false // violation
   * };
   *
   * String[][] text = {{},{},}; // OK
   *
   * double[][] decimals = {
   * {0.5, 2.3, 1.1,}, // OK
   * {1.7, 1.9, 0.6}, // violation
   * {0.8, 7.4, 6.5} // violation
   * }; // violation, previous line misses a comma
   *
   * char[] chars = {'a', 'b', 'c'  // violation
   *   };
   *
   * String[] letters = {
   *   "a", "b", "c"}; // violation
   *
   * int[] a1 = new int[]{
   *   1,
   *   2
   *   ,
   * }; // OK
   *
   * int[] a2 = new int[]{
   *   1,
   *   2
   *   ,}; // OK
   * </pre>
   * <p>
   * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
   * </p>
   * <p>
   * Violation Message Keys:
   * </p>
   * <ul>
   * <li>
   * {@code array.trailing.comma}
   * </li>
   * </ul>
   *
   * @since 3.2
   */
  @StatelessCheck
  public class ArrayTrailingCommaCheck extends AbstractCheck {
  
      /**
       * A key is pointing to the warning message text in "messages.properties"
       * file.
       */
      public static final String MSG_KEY = "array.trailing.comma";
  
      /**
       * Control whether to always check for a trailing comma, even when an array is inline.
       */
      private boolean alwaysDemandTrailingComma;
  
      /**
       * Setter to control whether to always check for a trailing comma, even when an array is inline.
       *
       * @param alwaysDemandTrailingComma whether to always check for a trailing comma.
       */
      public void setAlwaysDemandTrailingComma(boolean alwaysDemandTrailingComma) {
          this.alwaysDemandTrailingComma = alwaysDemandTrailingComma;
      }
  
      @Override
      public int[] getDefaultTokens() {
          return getRequiredTokens();
      }
  
      @Override
      public int[] getAcceptableTokens() {
          return getRequiredTokens();
      }
  
      @Override
      public int[] getRequiredTokens() {
          return new int[] {TokenTypes.ARRAY_INIT};
      }
  
      @Override
      public void visitToken(DetailAST arrayInit) {
          final DetailAST rcurly = arrayInit.findFirstToken(TokenTypes.RCURLY);
          final DetailAST previousSibling = rcurly.getPreviousSibling();
  
          if (arrayInit.getChildCount() != 1
                  && (alwaysDemandTrailingComma
                      || !TokenUtil.areOnSameLine(rcurly, previousSibling)
                          && !TokenUtil.areOnSameLine(arrayInit, previousSibling))
                  && previousSibling.getType() != TokenTypes.COMMA) {
              log(previousSibling, MSG_KEY);
          }
      }
  
  }
  