1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2026 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ///////////////////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.checks;
21
22 import com.puppycrawl.tools.checkstyle.StatelessCheck;
23 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26
27 /**
28 * <div>
29 * Checks that all numerical literal prefixes, infixes, and suffixes are written
30 * using lowercase letters (for example prefixes : {@code 0x, 0b},
31 * infixes : {@code e, p}, suffixes : {@code f, d}).
32 * This convention follows the
33 * <a href="https://cr.openjdk.org/~alundblad/styleguide/index-v6.html#toc-literals">
34 * OpenJDK Style Guide</a>.
35 * </div>
36 *
37 * <p><b>ATTENTION:</b></p>
38 *
39 * <p>This check ignores the {@code L} suffix for long literals,
40 * as using an uppercase {@code L} is a widely accepted and recommended
41 * practice to avoid confusion with the digit {@code 1}.</p>
42 *
43 * @since 13.2.0
44 */
45 @StatelessCheck
46 public class NumericalPrefixesInfixesSuffixesCharacterCaseCheck extends AbstractCheck {
47
48 /**
49 * A key is pointing to the warning message text in "messages.properties"
50 * file.
51 */
52 public static final String MSG_PREFIX = "numerical.literal.prefix";
53
54 /**
55 * A key is pointing to the warning message text in "messages.properties"
56 * file.
57 */
58 public static final String MSG_INFIX = "numerical.literal.infix";
59
60 /**
61 * A key is pointing to the warning message text in "messages.properties"
62 * file.
63 */
64 public static final String MSG_SUFFIX = "numerical.literal.suffix";
65
66 @Override
67 public int[] getDefaultTokens() {
68 return getRequiredTokens();
69 }
70
71 @Override
72 public int[] getAcceptableTokens() {
73 return getRequiredTokens();
74 }
75
76 @Override
77 public int[] getRequiredTokens() {
78 return new int[] {TokenTypes.NUM_LONG, TokenTypes.NUM_INT,
79 TokenTypes.NUM_FLOAT, TokenTypes.NUM_DOUBLE,
80 };
81 }
82
83 @Override
84 public void visitToken(DetailAST ast) {
85 final String text = ast.getText();
86 final boolean isHex = text.startsWith("0x");
87 if (text.startsWith("0X") || text.startsWith("0B")) {
88 log(ast, MSG_PREFIX);
89 }
90 else if (!isHex && text.contains("E") || text.contains("P")) {
91 log(ast, MSG_INFIX);
92 }
93 else if ((text.endsWith("F") || text.endsWith("D")) && (!isHex || text.contains("p"))) {
94 log(ast, MSG_SUFFIX);
95 }
96 }
97 }