diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md index d6468d04f5..7513c59ba7 100644 --- a/docs/pages/next_major_development.md +++ b/docs/pages/next_major_development.md @@ -65,7 +65,7 @@ by it was inconsistent, and ultimately that level of nesting was unnecessary. * As is usual, use the designer to explore the new AST structure * {% jdoc_old jast::ASTPrimaryPrefix %} and {% jdoc_old jast::ASTPrimarySuffix %} are not nodes anymore. -Subtrees for expressions appear to be left-recursive now. For example, +Subtrees for primary expressions appear to be left-recursive now. For example, ```java new Foo().bar.foo(1) @@ -120,6 +120,23 @@ give you the information you need quickly. TODO write a summary of changes in the javadoc of the package, will be more accessible. +Note: this doesn't affect binary expressions like {% jdoc jast::ASTAdditiveExpression %}. +E.g. `a+b+c` is not parsed as +``` +AdditiveExpression ++ AdditiveExpression + + (a) + + (b) ++ (c) +``` +It's still +``` +AdditiveExpression ++ (a) ++ (b) ++ (c) +``` +which is easier to navigate, especially from XPath. ## New API support guidelines diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java index 91427c8837..7eda085311 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java @@ -5,19 +5,22 @@ package net.sourceforge.pmd.lang.java.ast; -public class ASTBooleanLiteral extends AbstractJavaTypeNode { +public final class ASTBooleanLiteral extends AbstractJavaTypeNode implements ASTLiteral { private boolean isTrue; - public ASTBooleanLiteral(int id) { + + ASTBooleanLiteral(int id) { super(id); } - public ASTBooleanLiteral(JavaParser p, int id) { + + ASTBooleanLiteral(JavaParser p, int id) { super(p, id); } - public void setTrue() { + + void setTrue() { isTrue = true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCharLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCharLiteral.java index 0248973251..163ec0b1a2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCharLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCharLiteral.java @@ -8,6 +8,11 @@ package net.sourceforge.pmd.lang.java.ast; import org.apache.commons.lang3.StringEscapeUtils; +/** + * Represents a character literal. The image of this node can be the literal as it appeared + * in the source, but JavaCC performs its own unescaping and some escapes may be lost. At the + * very least it has delimiters. {@link #getUnescapedValue()} allows to recover the actual runtime value. + */ public final class ASTCharLiteral extends AbstractJavaTypeNode implements ASTLiteral { @@ -21,9 +26,7 @@ public final class ASTCharLiteral extends AbstractJavaTypeNode implements ASTLit } - /** - * Accept the visitor. * - */ + @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -39,9 +42,10 @@ public final class ASTCharLiteral extends AbstractJavaTypeNode implements ASTLit /** * Gets the char value of this literal. */ - public char getEscapedValue() { - // TODO - return StringEscapeUtils.unescapeJava(getImage()).charAt(0); + public char getUnescapedValue() { + String image = getImage(); + String woDelims = image.substring(1, image.length() - 1); + return StringEscapeUtils.unescapeJava(woDelims).charAt(0); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java index b591a37bac..b2c397598e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java @@ -15,6 +15,7 @@ package net.sourceforge.pmd.lang.java.ast; * | {@link ASTCharLiteral CharLiteral} * | {@link ASTBooleanLiteral BooleanLiteral} * | {@link ASTNullLiteral NullLiteral} + * | {@link ASTClassLiteral ClassLiteral} * * */ @@ -44,6 +45,21 @@ public interface ASTLiteral extends ASTPrimaryExpression { } + /** + * Returns true if this is a {@linkplain ASTNullLiteral class literal}. + */ + default boolean isClassLiteral() { + return this instanceof ASTClassLiteral; + } + + + /** + * Returns true if this is a {@linkplain ASTBooleanLiteral boolean literal}. + */ + default boolean isBooleanLiteral() { + return this instanceof ASTBooleanLiteral; + } + /** * Returns true if this is a {@linkplain ASTNumericLiteral numeric literal} * of any kind. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNumericLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNumericLiteral.java index ab5d681909..342ea70456 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNumericLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNumericLiteral.java @@ -7,7 +7,6 @@ package net.sourceforge.pmd.lang.java.ast; import java.math.BigInteger; import java.util.Locale; -import java.util.regex.Pattern; /** @@ -17,7 +16,7 @@ public class ASTNumericLiteral extends AbstractJavaTypeNode implements ASTLitera // by default is double - // TODO this can be done in jjtCloseNodeScope + // TODO all of this can be done in jjtCloseNodeScope private boolean isInt; private boolean isFloat; @@ -60,9 +59,7 @@ public class ASTNumericLiteral extends AbstractJavaTypeNode implements ASTLitera public boolean isIntLiteral() { String image = getImage(); if (isInt && image != null && image.length() > 0) { - if (!image.endsWith("l") && !image.endsWith("L")) { - return true; - } + return !image.endsWith("l") && !image.endsWith("L"); } return false; } @@ -77,9 +74,7 @@ public class ASTNumericLiteral extends AbstractJavaTypeNode implements ASTLitera public boolean isLongLiteral() { String image = getImage(); if (isInt && image != null && image.length() > 0) { - if (image.endsWith("l") || image.endsWith("L")) { - return true; - } + return image.endsWith("l") || image.endsWith("L"); } return false; } @@ -91,9 +86,7 @@ public class ASTNumericLiteral extends AbstractJavaTypeNode implements ASTLitera String image = getImage(); if (isFloat && image != null && image.length() > 0) { char lastChar = image.charAt(image.length() - 1); - if (lastChar == 'f' || lastChar == 'F') { - return true; - } + return lastChar == 'f' || lastChar == 'F'; } return false; } @@ -109,9 +102,7 @@ public class ASTNumericLiteral extends AbstractJavaTypeNode implements ASTLitera String image = getImage(); if (isFloat && image != null && image.length() > 0) { char lastChar = image.charAt(image.length() - 1); - if (lastChar == 'd' || lastChar == 'D' || Character.isDigit(lastChar) || lastChar == '.') { - return true; - } + return lastChar == 'd' || lastChar == 'D' || Character.isDigit(lastChar) || lastChar == '.'; } return false; } @@ -126,7 +117,8 @@ public class ASTNumericLiteral extends AbstractJavaTypeNode implements ASTLitera image = image.substring(1); } - if (image.endsWith("l")) { + char last = image.charAt(image.length()-1); + if (last == 'l' || last == 'd' || last == 'f') { image = image.substring(0, image.length() - 1); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java index 3a28288cd5..f3d6c208ee 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java @@ -9,8 +9,10 @@ import org.apache.commons.lang3.StringEscapeUtils; /** - * Represents a string literal. The image of this node is the literal as it appeared - * in the source. {@link #getEscapedValue()} allows to recover the actual runtime value. + * Represents a string literal. The image of this node can be the literal as it appeared + * in the source, but JavaCC performs its own unescaping and some escapes may be lost. + * At the very least it has delimiters. {@link #getUnescapedValue()} allows to recover + * the actual runtime value. */ public final class ASTStringLiteral extends AbstractJavaTypeNode implements ASTLiteral { @@ -25,6 +27,42 @@ public final class ASTStringLiteral extends AbstractJavaTypeNode implements ASTL } + private String reconstructedImage = null; + + + @Override + public String getImage() { + if (reconstructedImage == null) { + reconstructedImage = getEscapedStringLiteral(super.getImage()); + } + return reconstructedImage; + } + + + /** + * Tries to reconstruct the original string literal. If the original length + * is greater than the parsed String literal, then probably some unicode + * escape sequences have been used. + */ + private String getEscapedStringLiteral(String javaccEscaped) { + int fullLength = getEndColumn() - getBeginColumn(); + if (fullLength > javaccEscaped.length()) { + StringBuilder result = new StringBuilder(fullLength); + for (int i = 0; i < javaccEscaped.length(); i++) { + char c = javaccEscaped.charAt(i); + if (c < 0x20 || c > 0xff || javaccEscaped.length() == 1) { + String hex = "0000" + Integer.toHexString(c); + result.append("\\u").append(hex.substring(hex.length() - 4)); + } else { + result.append(c); + } + } + return result.toString(); + } + return javaccEscaped; + } + + /** * Accept the visitor. * */ @@ -43,8 +81,10 @@ public final class ASTStringLiteral extends AbstractJavaTypeNode implements ASTL /** * Returns the value without delimiters and unescaped. */ - public String getEscapedValue() { - return StringEscapeUtils.unescapeJava(getImage()); + public String getUnescapedValue() { + String image = getImage(); + String woDelims = image.substring(1, image.length() - 1); + return StringEscapeUtils.unescapeJava(woDelims); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java index dedcd57b6d..0eb41fc602 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java @@ -177,7 +177,7 @@ public class AvoidDuplicateLiteralsRule extends AbstractJavaRule { if (occurrences.size() >= threshold) { ASTLiteral first = occurrences.get(0); if (first instanceof ASTStringLiteral) { - String rawImage = ((ASTStringLiteral) first).getEscapedValue(); + String rawImage = ((ASTStringLiteral) first).getUnescapedValue(); Object[] args = {rawImage, occurrences.size(), first.getBeginLine(),}; addViolation(data, first, args); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AppendCharacterWithCharRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AppendCharacterWithCharRule.java index 8474cd0f7b..dcb1d4b01c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AppendCharacterWithCharRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AppendCharacterWithCharRule.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.performance; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; import net.sourceforge.pmd.lang.java.ast.ASTLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; import net.sourceforge.pmd.lang.java.ast.ASTStringLiteral; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; @@ -32,7 +31,7 @@ public class AppendCharacterWithCharRule extends AbstractJavaRule { return data; } - if (((ASTStringLiteral) node).getEscapedValue().length() == 1) { + if (((ASTStringLiteral) node).getUnescapedValue().length() == 1) { if (!InefficientStringBufferingRule.isInStringBufferOperation(node, 8, "append")) { return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseIndexOfCharRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseIndexOfCharRule.java index 807306cc7e..ad2311bdf2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseIndexOfCharRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseIndexOfCharRule.java @@ -5,7 +5,6 @@ package net.sourceforge.pmd.lang.java.rule.performance; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTStringLiteral; import net.sourceforge.pmd.lang.java.rule.AbstractPoorMethodCall; @@ -38,7 +37,7 @@ public class UseIndexOfCharRule extends AbstractPoorMethodCall { @Override protected boolean isViolationArgument(Node arg) { - return arg instanceof ASTStringLiteral && ((ASTStringLiteral) arg).getEscapedValue().length() == 1; + return arg instanceof ASTStringLiteral && ((ASTStringLiteral) arg).getUnescapedValue().length() == 1; } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java deleted file mode 100644 index 0d42b6db53..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import static net.sourceforge.pmd.lang.java.ParserTstUtil.getNodes; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.Set; - -import org.junit.Test; - -import net.sourceforge.pmd.PMD; - -public class ASTLiteralTest { - - @Test - public void testIsStringLiteral() { - Set literals = getNodes(ASTLiteral.class, TEST1); - assertTrue((literals.iterator().next()).isStringLiteral()); - } - - @Test - public void testIsNotStringLiteral() { - Set literals = getNodes(ASTLiteral.class, TEST2); - assertFalse((literals.iterator().next()).isStringLiteral()); - } - - @Test - public void testIsIntIntLiteral() { - Set literals = getNodes(ASTLiteral.class, TEST3); - assertTrue((literals.iterator().next()).isIntLiteral()); - } - - @Test - public void testIsIntLongLiteral() { - Set literals = getNodes(ASTLiteral.class, TEST4); - assertTrue((literals.iterator().next()).isLongLiteral()); - } - - @Test - public void testIsFloatFloatLiteral() { - Set literals = getNodes(ASTLiteral.class, TEST5); - assertTrue((literals.iterator().next()).isFloatLiteral()); - } - - @Test - public void testIsFloatDoubleLiteral() { - Set literals = getNodes(ASTLiteral.class, TEST6); - assertTrue((literals.iterator().next()).isDoubleLiteral()); - } - - @Test - public void testIsCharLiteral() { - Set literals = getNodes(ASTLiteral.class, TEST7); - assertTrue((literals.iterator().next()).isCharLiteral()); - } - - @Test - public void testIntValueParsing() { - ASTNumericLiteral literal = new ASTNumericLiteral(1); - literal.setIntLiteral(); - literal.setImage("1___234"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(7); - assertEquals(1___234, literal.getValueAsInt()); - } - - @Test - public void testIntValueParsingBinary() { - ASTNumericLiteral literal = new ASTNumericLiteral(1); - literal.setIntLiteral(); - literal.setImage("0b0000_0010"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(7); - assertEquals(0b0000_0010, literal.getValueAsInt()); - } - - @Test - public void testIntValueParsingNegativeHexa() { - ASTNumericLiteral literal = new ASTNumericLiteral(1); - literal.setIntLiteral(); - literal.setImage("-0X0000_000f"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(7); - assertEquals(-0X0000_000f, literal.getValueAsInt()); - } - - @Test - public void testFloatValueParsingNegative() { - ASTNumericLiteral literal = new ASTNumericLiteral(1); - literal.setFloatLiteral(); - literal.setImage("-3_456.123_456"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(7); - assertEquals(-3_456.123_456f, literal.getValueAsFloat(), 0); - } - - @Test - public void testStringUnicodeEscapesNotEscaped() { - ASTStringLiteral literal = new ASTStringLiteral(1); - literal.setImage("abcüabc"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(7); - assertEquals("abcüabc", literal.getEscapedValue()); - assertEquals("abcüabc", literal.getImage()); - } - - @Test - public void testStringUnicodeEscapesInvalid() { - ASTStringLiteral literal = new ASTStringLiteral(1); - literal.setImage("abc\\uXYZAabc"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(12); - assertEquals("abc\\uXYZAabc", literal.getEscapedValue()); - assertEquals("abc\\uXYZAabc", literal.getImage()); - } - - @Test - public void testStringUnicodeEscapesValid() { - ASTStringLiteral literal = new ASTStringLiteral(1); - literal.setImage("abc\u1234abc"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(12); - assertEquals("abc\\u1234abc", literal.getEscapedValue()); - assertEquals("abcሴabc", literal.getImage()); - } - - @Test - public void testCharacterUnicodeEscapesValid() { - ASTCharLiteral literal = new ASTCharLiteral(1); - literal.setImage("\u0030"); - literal.testingOnlySetBeginColumn(1); - literal.testingOnlySetEndColumn(6); - assertEquals("\\u0030", literal.getEscapedValue()); - assertEquals("0", literal.getImage()); - } - - private static final String TEST1 = "public class Foo {" + PMD.EOL + " String x = \"foo\";" + PMD.EOL + "}"; - - private static final String TEST2 = "public class Foo {" + PMD.EOL + " int x = 42;" + PMD.EOL + "}"; - - private static final String TEST3 = "public class Foo {" + PMD.EOL + " int x = 42;" + PMD.EOL + "}"; - - private static final String TEST4 = "public class Foo {" + PMD.EOL + " long x = 42L;" + PMD.EOL + "}"; - - private static final String TEST5 = "public class Foo {" + PMD.EOL + " float x = 3.14159f;" + PMD.EOL + "}"; - - private static final String TEST6 = "public class Foo {" + PMD.EOL + " double x = 3.14159;" + PMD.EOL + "}"; - - private static final String TEST7 = "public class Foo {" + PMD.EOL + " char x = 'x';" + PMD.EOL + "}"; -} diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt new file mode 100644 index 0000000000..cf0913664e --- /dev/null +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt @@ -0,0 +1,221 @@ +package net.sourceforge.pmd.lang.java.ast + +import io.kotlintest.shouldBe +import io.kotlintest.specs.FunSpec +import net.sourceforge.pmd.lang.ast.test.shouldBe + +/** + * @author Clément Fournier + * @since 7.0.0 + */ +class ASTLiteralTest : FunSpec({ + + testGroup("String literal") { + + "\"\"" should matchExpr { + it::isStringLiteral shouldBe true + it::getUnescapedValue shouldBe "" + it::getImage shouldBe "\"\"" + } + + "\"foo\"" should matchExpr { + it::getUnescapedValue shouldBe "foo" + it::getImage shouldBe "\"foo\"" + } + + "\"foo\\t\"" should matchExpr { + it::getUnescapedValue shouldBe "foo\t" + it::getImage shouldBe "\"foo\\t\"" + } + + } + + + testGroup("String literal escapes") { + "\"abc\u1234abc\"" should matchExpr { + it::getUnescapedValue shouldBe "abc\u1234abc" + it::getImage shouldBe "\"abc\u1234abc\"" + } + + "\"abc\\u1234abc\"" should matchExpr { + it::getUnescapedValue shouldBe "abc\u1234abc" + it::getImage shouldBe "\"abc\\u1234abc\"" + } + "\"abcüabc\"" should matchExpr { + it::getUnescapedValue shouldBe "abcüabc" + it::getImage shouldBe "\"abcüabc\"" + } + } + + + + testGroup("Char literal") { + + "'c'" should matchExpr { + it::isCharLiteral shouldBe true + it::getUnescapedValue shouldBe 'c' + it::getImage shouldBe "'c'" + } + + "'\t'" should matchExpr { + it::getUnescapedValue shouldBe '\t' + it::getImage shouldBe "'\t'" + } + + "'\\t'" should matchExpr { + it::getUnescapedValue shouldBe '\t' + it::getImage shouldBe "'\\t'" + } + } + + testGroup("Class literals") { + + "void.class" should matchExpr { + it::isClassLiteral shouldBe true + it::isVoid shouldBe true + it.typeNode.shouldBeEmpty() + } + + "Integer.class" should matchExpr { + it::isClassLiteral shouldBe true + it::isVoid shouldBe false + + it.typeNode shouldBePresent child {} + } + + "int.class" should matchExpr { + it::isVoid shouldBe false + + it.typeNode shouldBePresent child {} + } + + "int[].class" should matchExpr { + it::isVoid shouldBe false + + it.typeNode shouldBePresent child { + it.elementType shouldBe child {} + it.dimensions shouldBe child { + it.size shouldBe 1 + + child {} + } + } + } + + } + + + testGroup("Boolean literals") { + + "true" should matchExpr { + it::isBooleanLiteral shouldBe true + it::isTrue shouldBe true + } + + "false" should matchExpr { + it::isBooleanLiteral shouldBe true + it::isTrue shouldBe false + } + } + + testGroup("Null literal") { + + "null" should matchExpr { + it::isBooleanLiteral shouldBe false + it::isStringLiteral shouldBe false + it::isNullLiteral shouldBe true + } + } + + testGroup("Numeric literals") { + + "12" should matchExpr { + it::isStringLiteral shouldBe false + it::isCharLiteral shouldBe false + it::isNumericLiteral shouldBe true + it::isIntLiteral shouldBe true + it::getValueAsInt shouldBe 12 + it::getValueAsLong shouldBe 12L + it::getValueAsFloat shouldBe 12.0f + it::getValueAsDouble shouldBe 12.0 + it::getImage shouldBe "12" + } + + "1___234" should matchExpr { + it::isCharLiteral shouldBe false + it::isNumericLiteral shouldBe true + it::isIntLiteral shouldBe true + it::getValueAsInt shouldBe 1234 + it::getImage shouldBe "1___234" + } + + "0b0000_0010" should matchExpr { + it::isCharLiteral shouldBe false + it::isNumericLiteral shouldBe true + it::isIntLiteral shouldBe true + it::getValueAsInt shouldBe 2 + it::getImage shouldBe "0b0000_0010" + } + + "-0X0000_000f" should matchExpr { + it::isCharLiteral shouldBe false + it::isNumericLiteral shouldBe true + it::isIntLiteral shouldBe true + it::getValueAsInt shouldBe -15 + it::getImage shouldBe "-0X0000_000f" + } + + "12l" should matchExpr { + it::isCharLiteral shouldBe false + it::isNumericLiteral shouldBe true + it::isIntLiteral shouldBe false + it::isLongLiteral shouldBe true + it::getValueAsInt shouldBe 12 + it::getValueAsLong shouldBe 12L + it::getValueAsFloat shouldBe 12.0f + it::getValueAsDouble shouldBe 12.0 + it::getImage shouldBe "12l" + } + + "12L" should matchExpr { + it::isLongLiteral shouldBe true + it::getValueAsInt shouldBe 12 + it::getValueAsLong shouldBe 12L + it::getImage shouldBe "12L" + } + + "12d" should matchExpr { + it::isIntLiteral shouldBe false + it::isNumericLiteral shouldBe true + it::isDoubleLiteral shouldBe true + it::getValueAsInt shouldBe 12 + it::getValueAsFloat shouldBe 12.0f + it::getValueAsDouble shouldBe 12.0 + it::getImage shouldBe "12d" + } + + "12f" should matchExpr { + it::isIntLiteral shouldBe false + it::isDoubleLiteral shouldBe false + it::isNumericLiteral shouldBe true + it::isFloatLiteral shouldBe true + it::getValueAsInt shouldBe 12 + it::getValueAsFloat shouldBe 12.0f + it::getValueAsDouble shouldBe 12.0 + it::getImage shouldBe "12f" + } + + "-3_456.123_456" should matchExpr { + it::isIntLiteral shouldBe false + it::isDoubleLiteral shouldBe true + it::isNumericLiteral shouldBe true + it::isFloatLiteral shouldBe false + it::getValueAsInt shouldBe -3456 + it::getValueAsFloat shouldBe -3456.123456f + it::getValueAsDouble shouldBe -3456.123456 + it::getImage shouldBe "-3_456.123_456" + } + + } + +})