001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2025 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 java.util.ArrayList; 023import java.util.List; 024import java.util.Locale; 025import java.util.Set; 026 027import com.puppycrawl.tools.checkstyle.StatelessCheck; 028import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 029import com.puppycrawl.tools.checkstyle.api.DetailAST; 030import com.puppycrawl.tools.checkstyle.api.TokenTypes; 031 032/** 033 * <div> Checks that hexadecimal literals are defined using uppercase letters {@code (A-F)} 034 * rather than lowercase {@code (a-f)}. 035 * This improves readability and avoids confusion with suffixes like {@code f}(float) 036 * and {@code d}(double). For example, use {@code 0xFF} instead of {@code 0xff}. 037 * All other numerical prefixes, infixes, and suffixes (such as {@code 0x}, {@code 0b}, 038 * {@code f}, {@code d}) should remain lowercase. 039 * This convention follows the 040 * <a href="https://cr.openjdk.org/~alundblad/styleguide/index-v6.html#toc-literals"> 041 * OpenJDK Style Guide</a>. 042 * </div> 043 * 044 * <p> 045 * For example, {@code 0xAF} is valid, but {@code 0xaf} is not. 046 * </p> 047 * 048 * <p> 049 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 050 * </p> 051 * 052 * <p> 053 * Violation Message Keys: 054 * </p> 055 * 056 * <ul> 057 * <li> 058 * {@code hex.Literal} 059 * </li> 060 * </ul> 061 * 062 * @since 11.1.0 063 */ 064@StatelessCheck 065public class HexLiteralCaseCheck extends AbstractCheck { 066 067 /** 068 * A key is pointing to the warning message text in "messages.properties" 069 * file. 070 */ 071 public static final String MSG_KEY = "hex.Literal"; 072 /** 073 * Lowercase hexadecimal characters that are considered violations 074 * when used in hexadecimal literals (e.g., 0x1a). Hex digits should be uppercase. 075 */ 076 private final Set<Character> hexChars = Set.of('a', 'b', 'c', 'd', 'e', 'f'); 077 078 @Override 079 public int[] getDefaultTokens() { 080 return getRequiredTokens(); 081 } 082 083 @Override 084 public int[] getAcceptableTokens() { 085 return getRequiredTokens(); 086 } 087 088 @Override 089 public int[] getRequiredTokens() { 090 return new int[] {TokenTypes.NUM_LONG, TokenTypes.NUM_INT}; 091 } 092 093 @Override 094 public void visitToken(DetailAST ast) { 095 if (ast.getText().toLowerCase(Locale.ROOT).startsWith("0x")) { 096 final char[] charArray = ast.getText().toCharArray(); 097 final List<Character> characterList = new ArrayList<>(charArray.length); 098 for (char letter : charArray) { 099 characterList.add(letter); 100 } 101 final boolean containLowerLetter = characterList.stream() 102 .anyMatch(hexChars::contains); 103 if (containLowerLetter) { 104 log(ast, MSG_KEY); 105 } 106 } 107 } 108}