• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 4515

27 Mar 2025 12:01PM UTC coverage: 77.853% (+0.06%) from 77.796%
4515

push

github

adangel
Fix #5590: [java] LiteralsFirstInComparisons with constant field (#5595)

Merge pull request #5595 from oowekyala:issue5590-literal-comparison

17580 of 23536 branches covered (74.69%)

Branch coverage included in aggregate %.

106 of 110 new or added lines in 11 files covered. (96.36%)

62 existing lines in 5 files now uncovered.

38483 of 48475 relevant lines covered (79.39%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.94
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNumericLiteral.java
1
/**
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang.java.ast;
6

7
import org.apache.commons.lang3.StringUtils;
8
import org.checkerframework.checker.nullness.qual.NonNull;
9
import org.checkerframework.checker.nullness.qual.Nullable;
10

11
import net.sourceforge.pmd.lang.document.Chars;
12
import net.sourceforge.pmd.lang.java.types.JPrimitiveType;
13

14

15
/**
16
 * A numeric literal of any type (double, int, long, float, etc).
17
 */
18
public final class ASTNumericLiteral extends AbstractLiteral implements ASTLiteral {
19

20
    /**
21
     * True if this is an integral literal, ie int OR long,
22
     * false if this is a floating-point literal, ie float OR double.
23
     */
24
    private boolean isIntegral;
25
    private boolean is64bits;
26
    private long longValue;
27
    private double doubleValue;
28

29

30
    ASTNumericLiteral(int id) {
31
        super(id);
1✔
32
    }
1✔
33

34

35
    @Override
36
    protected <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data) {
37
        return visitor.visit(this, data);
1✔
38
    }
39

40
    @Override
41
    public Chars getLiteralText() {
42
        return super.getLiteralText();
1✔
43
    }
44

45
    @Override
46
    public @NonNull Number getConstValue() {
47
        return (Number) super.getConstValue();
1✔
48
    }
49

50
    /**
51
     * @deprecated Since 7.12.0. See super method. This override is needed due to covariant return type change.
52
     */
53
    @Override
54
    @Deprecated
55
    protected @Nullable Number buildConstValue() {
NEW
56
        return (Number) super.buildConstValue();
×
57
    }
58

59
    @Override
60
    public @NonNull JPrimitiveType getTypeMirror() {
61
        return (JPrimitiveType) super.getTypeMirror();
1✔
62
    }
63

64
    void setIntLiteral() {
65
        this.isIntegral = true;
1✔
66
    }
1✔
67

68

69
    void setFloatLiteral() {
70
        this.isIntegral = false;
1✔
71
    }
1✔
72

73
    @Override
74
    public void jjtClose() {
75
        super.jjtClose();
1✔
76

77
        Chars image = getLiteralText();
1✔
78
        char lastChar = image.charAt(image.length() - 1);
1✔
79
        if (isIntegral) {
1✔
80
            is64bits = lastChar == 'l' || lastChar == 'L';
1✔
81
            longValue = parseIntegralValue(image);
1✔
82
            doubleValue = (double) longValue;
1✔
83
        } else {
84
            is64bits = !(lastChar == 'f' || lastChar == 'F');
1✔
85
            doubleValue = Double.parseDouble(StringUtils.remove(image.toString(), '_'));
1✔
86
            longValue = (long) doubleValue;
1✔
87
        }
88
    }
1✔
89

90

91
    public boolean isIntLiteral() {
92
        return isIntegral && !is64bits;
1✔
93
    }
94

95
    public boolean isLongLiteral() {
96
        return isIntegral && is64bits;
1✔
97
    }
98

99
    public boolean isFloatLiteral() {
100
        return !isIntegral && !is64bits;
1✔
101
    }
102

103
    public boolean isDoubleLiteral() {
104
        return !isIntegral && is64bits;
1✔
105
    }
106

107

108
    /**
109
     * Returns true if this is an integral literal, ie either a long or
110
     * an integer literal. Otherwise, this is a floating point literal.
111
     */
112
    public boolean isIntegral() {
113
        return isIntegral;
1✔
114
    }
115

116
    /**
117
     * Returns the base of the literal, eg 8 for an octal literal,
118
     * 10 for a decimal literal, etc. By convention this returns 10
119
     * for the literal {@code 0} (which can really be any base).
120
     */
121
    public int getBase() {
122
        return getBase(getLiteralText(), isIntegral());
1✔
123
    }
124

125
    static int getBase(Chars image, boolean isIntegral) {
126
        if (image.length() > 1 && image.charAt(0) == '0') {
1✔
127
            switch (image.charAt(1)) {
1✔
128
            case 'x':
129
            case 'X':
130
                return 16;
1✔
131
            case 'b':
132
            case 'B':
133
                return 2;
1✔
134
            default:
135
                return isIntegral ? 8 : 10;
1✔
136
            }
137
        }
138
        return 10;
1✔
139
    }
140

141
    // From 7.0.x, these methods always return a meaningful number, the
142
    // closest we can find.
143
    // In 6.0.x, eg getValueAsInt was giving up when this was a double.
144

145
    public int getValueAsInt() {
146
        return (int) longValue;
1✔
147
    }
148

149

150
    public long getValueAsLong() {
151
        return longValue;
1✔
152
    }
153

154

155
    public float getValueAsFloat() {
156
        return (float) doubleValue;
1✔
157
    }
158

159

160
    public double getValueAsDouble() {
161
        return doubleValue;
1✔
162
    }
163

164
    /**
165
     * Parse an int or long literal into a long. This avoids creating
166
     * and discarding a BigInteger, and avoids exceptions if the literal
167
     * is malformed.
168
     *
169
     * <p>Invalid literals or overflows result in {@code 0L}.
170
     */
171
    static long parseIntegralValue(Chars image) {
172
        final int base = getBase(image, true);
1✔
173
        if (base == 8) {
1✔
174
            image = image.subSequence(1); // 0
1✔
175
        } else if (base != 10) {
1✔
176
            image = image.subSequence(2); // 0x / 0b
1✔
177
        }
178

179
        int length = image.length();
1✔
180
        char lastChar = image.charAt(length - 1);
1✔
181
        if (lastChar == 'l' || lastChar == 'L') {
1✔
182
            length--;
1✔
183
        }
184

185
        try {
186
            String literalImage = image.substring(0, length).replaceAll("_", "");
1✔
187
            return Long.parseUnsignedLong(literalImage, base);
1✔
188
        } catch (NumberFormatException e) {
1✔
189
            // invalid literal or overflow
190
            return 0L;
1✔
191
        }
192
    }
193
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc