[java] Remove support for Java 14 preview

This commit is contained in:
Andreas Dangel
2021-02-15 19:51:48 +01:00
parent 3b151e31c4
commit 2ec77ad02f
12 changed files with 19 additions and 431 deletions

View File

@ -1,4 +1,5 @@
/**
* Remove support for Java 14 preview language features
* JEP 397: Sealed Classes (Second Preview) for Java16 Preview
* JEP 395: Records for Java16
* JEP 394: Pattern Matching for instanceof for Java16
@ -383,8 +384,8 @@ public class JavaParser {
}
private void checkforBadInstanceOfPattern() {
if (!(jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16)) {
throwParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java >= 16");
if (!(jdkVersion == 15 && preview || jdkVersion >= 16)) {
throwParseException("Pattern Matching for instanceof is only supported with Java 15 Preview and Java >= 16");
}
}
@ -431,8 +432,8 @@ public class JavaParser {
if (jdkVersion >= 14 && "yield".equals(image)) {
throwParseException("With JDK 14, 'yield' is a contextual keyword and cannot be used for type declarations!");
}
if ((jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16) && "record".equals(image)) {
throwParseException("With JDK 14 Preview and JDK 15 Preview and Java >= 16, 'record' is a contextual keyword and cannot be used for type declarations!");
if ((jdkVersion == 15 && preview || jdkVersion >= 16) && "record".equals(image)) {
throwParseException("With JDK 15 Preview and Java >= 16, 'record' is a contextual keyword and cannot be used for type declarations!");
}
if ((jdkVersion == 15 && preview || jdkVersion == 16 && preview) && "sealed".equals(image)) {
throwParseException("With JDK 15 Preview and JDK 16 Preview, 'sealed' is a contextual keyword and cannot be used for type declarations!");
@ -474,31 +475,31 @@ public class JavaParser {
}
private void checkForTextBlockLiteral() {
if (jdkVersion < 15 && !preview) {
throwParseException("Text block literals are only supported with Java 14 Preview and Java >= 15");
if (!(jdkVersion >= 15)) {
throwParseException("Text block literals are only supported with Java >= 15");
}
}
private void checkForNewStringSpaceEscape(String s) {
if ((jdkVersion < 15 && !preview) && s.contains("\\s") && !s.contains("\\\\s")) {
throwParseException("The escape sequence \"\\s\" is only supported with Java 14 Preview and Java >= 15");
if (!(jdkVersion >= 15) && s.contains("\\s") && !s.contains("\\\\s")) {
throwParseException("The escape sequence \"\\s\" is only supported with Java >= 15");
}
}
private void checkForRecordType() {
if (!isRecordTypeSupported()) {
throwParseException("Records are only supported with Java 14 Preview and Java 15 Preview and Java >= 16");
throwParseException("Records are only supported with Java 15 Preview and Java >= 16");
}
}
private void checkForLocalInterfaceOrEnumType() {
if (!isRecordTypeSupported()) {
throwParseException("Local interfaces and enums are only supported with Java 14 Preview and Java 15 Preview and Java >= 16");
throwParseException("Local interfaces and enums are only supported with Java 15 Preview and Java >= 16");
}
}
private boolean isRecordTypeSupported() {
return jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16;
return jdkVersion == 15 && preview || jdkVersion >= 16;
}
private boolean isSealedClassSupported() {

View File

@ -28,7 +28,6 @@ public class JavaLanguageModule extends BaseLanguageModule {
addVersion("12", new JavaLanguageHandler(12));
addVersion("13", new JavaLanguageHandler(13));
addVersion("14", new JavaLanguageHandler(14));
addVersion("14-preview", new JavaLanguageHandler(14, true));
addVersion("15", new JavaLanguageHandler(15));
addVersion("15-preview", new JavaLanguageHandler(15, true));
addDefaultVersion("16", new JavaLanguageHandler(16)); // 16 is the default

View File

@ -1,189 +0,0 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind;
/**
* Tests new java14 preview features.
*/
public class Java14PreviewTest {
private final JavaParsingHelper java14 =
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14")
.withResourceContext(Java14Test.class, "jdkversiontests/java14/");
private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview");
private final JavaParsingHelper java13 = java14.withDefaultVersion("13");
@Test
public void textBlocks() {
ASTCompilationUnit compilationUnit = java14p.parseResource("TextBlocks.java");
List<ASTLiteral> literals = compilationUnit.findDescendantsOfType(ASTLiteral.class);
Assert.assertEquals(22, literals.size());
Assert.assertFalse(literals.get(2).isTextBlock());
Assert.assertFalse(literals.get(12).isTextBlock());
Assert.assertFalse(literals.get(17).isTextBlock());
Assert.assertFalse(literals.get(18).isTextBlock());
Assert.assertFalse(literals.get(20).isTextBlock());
Assert.assertFalse(literals.get(21).isTextBlock());
List<ASTLiteral> textBlocks = new ArrayList<>();
for (ASTLiteral literal : literals) {
if (literal.isTextBlock()) {
textBlocks.add(literal);
}
}
Assert.assertEquals(16, textBlocks.size());
Assert.assertEquals("\"\"\"\n"
+ " <html> \n"
+ " <body>\n"
+ " <p>Hello, world</p> \n"
+ " </body> \n"
+ " </html> \n"
+ " \"\"\"",
textBlocks.get(0).getImage());
Assert.assertEquals("<html>\n"
+ " <body>\n"
+ " <p>Hello, world</p>\n"
+ " </body>\n"
+ "</html>\n", textBlocks.get(0).getTextBlockContent());
// Note: More tests are in ASTLiteralTest.
}
@Test(expected = ParseException.class)
public void textBlocksBeforeJava14PreviewShouldFail() {
java13.parseResource("TextBlocks.java");
}
@Test(expected = ParseException.class)
public void stringEscapeSequenceShouldFail() {
java14.parse("class Foo { String s =\"a\\sb\"; }");
}
@Test
public void patternMatchingInstanceof() {
ASTCompilationUnit compilationUnit = java14p.parseResource("PatternMatchingInstanceof.java");
List<ASTInstanceOfExpression> instanceOfExpressions = compilationUnit.findDescendantsOfType(ASTInstanceOfExpression.class);
Assert.assertEquals(4, instanceOfExpressions.size());
for (ASTInstanceOfExpression expr : instanceOfExpressions) {
Assert.assertTrue(expr.getChild(1) instanceof ASTTypePattern);
ASTVariableDeclaratorId variable = expr.getChild(1).getFirstChildOfType(ASTVariableDeclaratorId.class);
Assert.assertEquals(String.class, variable.getType());
Assert.assertEquals("s", variable.getVariableName());
Assert.assertTrue(variable.isPatternBinding());
Assert.assertFalse(variable.isFinal());
// Note: these variables are not part of the symbol table
// See ScopeAndDeclarationFinder#visit(ASTVariableDeclaratorId, Object)
Assert.assertNull(variable.getNameDeclaration());
}
}
@Test(expected = ParseException.class)
public void patternMatchingInstanceofBeforeJava14PreviewShouldFail() {
java14.parseResource("PatternMatchingInstanceof.java");
}
@Test
public void recordPoint() {
ASTCompilationUnit compilationUnit = java14p.parseResource("Point.java");
ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class);
Assert.assertEquals("Point", recordDecl.getImage());
Assert.assertFalse(recordDecl.isNested());
List<ASTRecordComponent> components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class)
.findChildrenOfType(ASTRecordComponent.class);
Assert.assertEquals(2, components.size());
Assert.assertEquals("x", components.get(0).getVarId().getImage());
Assert.assertEquals("y", components.get(1).getVarId().getImage());
Assert.assertNull(components.get(0).getVarId().getNameDeclaration().getAccessNodeParent());
Assert.assertEquals(Integer.TYPE, components.get(0).getVarId().getNameDeclaration().getType());
Assert.assertEquals("int", components.get(0).getVarId().getNameDeclaration().getTypeImage());
}
@Test(expected = ParseException.class)
public void recordPointBeforeJava14PreviewShouldFail() {
java14.parseResource("Point.java");
}
@Test(expected = ParseException.class)
public void recordCtorWithThrowsShouldFail() {
java14p.parse(" record R {"
+ " R throws IOException {}"
+ " }");
}
@Test
public void innerRecords() {
ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java");
List<ASTRecordDeclaration> recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class, true);
Assert.assertEquals(7, recordDecls.size());
ASTRecordDeclaration complex = recordDecls.get(0);
Assert.assertEquals("MyComplex", complex.getSimpleName());
Assert.assertTrue(complex.isNested());
Assert.assertEquals(0, getComponent(complex, 0).findChildrenOfType(ASTAnnotation.class).size());
Assert.assertEquals(1, getComponent(complex, 1).findChildrenOfType(ASTAnnotation.class).size());
Assert.assertEquals(2, complex.getDeclarations().size());
Assert.assertTrue(complex.getDeclarations().get(0).getChild(1) instanceof ASTConstructorDeclaration);
Assert.assertTrue(complex.getDeclarations().get(1).getChild(0) instanceof ASTRecordDeclaration);
Assert.assertTrue(complex.getParent() instanceof ASTClassOrInterfaceBodyDeclaration);
ASTClassOrInterfaceBodyDeclaration complexParent = complex.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class);
Assert.assertEquals(DeclarationKind.RECORD, complexParent.getKind());
Assert.assertSame(complex, complexParent.getDeclarationNode());
ASTRecordDeclaration nested = recordDecls.get(1);
Assert.assertEquals("Nested", nested.getSimpleName());
Assert.assertTrue(nested.isNested());
ASTRecordDeclaration range = recordDecls.get(2);
Assert.assertEquals("Range", range.getSimpleName());
Assert.assertEquals(2, range.getComponentList().size());
List<ASTCompactConstructorDeclaration> rangeConstructors = range.findDescendantsOfType(ASTCompactConstructorDeclaration.class);
Assert.assertEquals(1, rangeConstructors.size());
Assert.assertEquals("Range", rangeConstructors.get(0).getImage());
Assert.assertTrue(rangeConstructors.get(0).getChild(0) instanceof ASTAnnotation);
Assert.assertEquals(2, range.getDeclarations().size());
ASTRecordDeclaration varRec = recordDecls.get(3);
Assert.assertEquals("VarRec", varRec.getSimpleName());
Assert.assertEquals("x", getComponent(varRec, 0).getVarId().getImage());
Assert.assertTrue(getComponent(varRec, 0).isVarargs());
Assert.assertEquals(2, getComponent(varRec, 0).findChildrenOfType(ASTAnnotation.class).size());
Assert.assertEquals(1, getComponent(varRec, 0).getTypeNode().findDescendantsOfType(ASTAnnotation.class).size());
ASTRecordDeclaration arrayRec = recordDecls.get(4);
Assert.assertEquals("ArrayRec", arrayRec.getSimpleName());
Assert.assertEquals("x", getComponent(arrayRec, 0).getVarId().getImage());
Assert.assertTrue(getComponent(arrayRec, 0).getVarId().hasArrayType());
ASTRecordDeclaration emptyRec = recordDecls.get(5);
Assert.assertEquals("EmptyRec", emptyRec.getSimpleName());
Assert.assertEquals(0, emptyRec.getComponentList().size());
ASTRecordDeclaration personRec = recordDecls.get(6);
Assert.assertEquals("PersonRecord", personRec.getSimpleName());
ASTImplementsList impl = personRec.getFirstChildOfType(ASTImplementsList.class);
Assert.assertEquals(2, impl.findChildrenOfType(ASTClassOrInterfaceType.class).size());
}
private ASTRecordComponent getComponent(ASTRecordDeclaration arrayRec, int index) {
return (ASTRecordComponent) arrayRec.getComponentList().getChild(index);
}
@Test(expected = ParseException.class)
public void recordIsARestrictedIdentifier() {
java14p.parse("public class record {}");
}
}

View File

@ -24,7 +24,6 @@ public class Java14Test {
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14")
.withResourceContext(Java14Test.class, "jdkversiontests/java14/");
private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview");
private final JavaParsingHelper java13 = java14.withDefaultVersion("13");
/**
@ -33,7 +32,6 @@ public class Java14Test {
@Test
public void switchExpressions() {
parseAndCheckSwitchExpression(java14);
parseAndCheckSwitchExpression(java14p);
}
/**
@ -131,7 +129,6 @@ public class Java14Test {
@Test
public void multipleCaseLabels() {
multipleCaseLabels(java14);
multipleCaseLabels(java14p);
}
private void multipleCaseLabels(JavaParsingHelper parser) {
@ -146,7 +143,6 @@ public class Java14Test {
@Test
public void switchRules() {
switchRules(java14);
switchRules(java14p);
}
private void switchRules(JavaParsingHelper parser) {
@ -173,7 +169,6 @@ public class Java14Test {
@Test
public void simpleSwitchExpressions() {
simpleSwitchExpressions(java14);
simpleSwitchExpressions(java14p);
}
private void simpleSwitchExpressions(JavaParsingHelper parser) {

View File

@ -12,16 +12,16 @@ import java.io.IOException
class ASTPatternTest : ParserTestSpec({
parserTest("Test patterns only available on JDK 14+15 (preview) and JDK16 and JDK16 (preview)",
javaVersions = JavaVersion.values().asList().minus(J14__PREVIEW).minus(J15__PREVIEW).minus(J16).minus(J16__PREVIEW)) {
parserTest("Test patterns only available on JDK 15 (preview) and JDK16 and JDK16 (preview)",
javaVersions = JavaVersion.values().asList().minus(J15__PREVIEW).minus(J16).minus(J16__PREVIEW)) {
expectParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java >= 16") {
expectParseException("Pattern Matching for instanceof is only supported with Java 15 Preview and Java >= 16") {
parseAstExpression("obj instanceof Class c")
}
}
parserTest("Test simple patterns", javaVersions = listOf(J14__PREVIEW, J15__PREVIEW, J16)) {
parserTest("Test simple patterns", javaVersions = listOf(J15__PREVIEW, J16)) {
importedTypes += IOException::class.java

View File

@ -20,7 +20,7 @@ enum class JavaVersion : Comparable<JavaVersion> {
J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11,
J12,
J13,
J14, J14__PREVIEW,
J14,
J15, J15__PREVIEW,
J16, J16__PREVIEW;

View File

@ -1,34 +0,0 @@
/**
*
* @see <a href="https://openjdk.java.net/jeps/305">JEP 305: Pattern Matching for instanceof (Preview)</a>
*/
public class PatternMatchingInstanceof {
private String s = "other string";
public void test() {
Object obj = "abc";
//obj = 1;
if (obj instanceof String s) {
System.out.println("a) obj == s: " + (obj == s)); // true
} else {
System.out.println("b) obj == s: " + (obj == s)); // false
}
if (!(obj instanceof String s)) {
System.out.println("c) obj == s: " + (obj == s)); // false
} else {
System.out.println("d) obj == s: " + (obj == s)); // true
}
if (obj instanceof String s && s.length() > 2) {
System.out.println("e) obj == s: " + (obj == s)); // true
}
if (obj instanceof String s || s.length() > 5) {
System.out.println("f) obj == s: " + (obj == s)); // false
}
}
public static void main(String[] args) {
new PatternMatchingInstanceof().test();
}
}

View File

@ -1,10 +0,0 @@
/**
* @see <a href="https://openjdk.java.net/jeps/359">JEP 359: Records (Preview)</a>
*/
public record Point(int x, int y) {
public static void main(String[] args) {
Point p = new Point(1, 2);
System.out.println("p = " + p);
}
}

View File

@ -1,61 +0,0 @@
import java.io.IOException;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* @see <a href="https://openjdk.java.net/jeps/359">JEP 359: Records (Preview)</a>
*/
public class Records {
@Target(ElementType.TYPE_USE)
@interface Nullable { }
@Target({ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@interface MyAnnotation { }
public record MyComplex(int real, @Deprecated int imaginary) {
// explicit declaration of a canonical constructor
@MyAnnotation
public MyComplex(@MyAnnotation int real, int imaginary) {
if (real > 100) throw new IllegalArgumentException("too big");
this.real = real;
this.imaginary = imaginary;
}
public record Nested(int a) {}
}
public record Range(int lo, int hi) {
// compact record constructor
@MyAnnotation
public Range {
if (lo > hi) /* referring here to the implicit constructor parameters */
throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi));
}
public void foo() { }
}
public record VarRec(@Nullable @Deprecated String @Nullable ... x) {}
public record ArrayRec(int x[]) {}
public record EmptyRec<Type>() {
public void foo() { }
public Type bar() { return null; }
public static void baz() {
EmptyRec<String> r = new EmptyRec<>();
System.out.println(r);
}
}
// see https://www.javaspecialists.eu/archive/Issue276.html
public interface Person {
String firstName();
String lastName();
}
public record PersonRecord(String firstName, String lastName)
implements Person, java.io.Serializable {
}
}

View File

@ -1,113 +0,0 @@
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
/**
* @see <a href="https://openjdk.java.net/jeps/368">JEP 368: Text Blocks (Second Preview)</a>
*/
public class TextBlocks {
public static void main(String[] args) throws Exception {
// note: there is trailing whitespace!!
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
System.out.println(html);
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";
System.out.println(query);
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("""
function hello() {
print('"Hello, world"');
}
hello();
""");
// Escape sequences
String htmlWithEscapes = """
<html>\r
<body>\r
<p>Hello, world</p>\r
</body>\r
</html>\r
""";
System.out.println(htmlWithEscapes);
String season = """
winter"""; // the six characters w i n t e r
String period = """
winter
"""; // the seven characters w i n t e r LF
String greeting =
"""
Hi, "Bob"
"""; // the ten characters H i , SP " B o b " LF
String salutation =
"""
Hi,
"Bob"
"""; // the eleven characters H i , LF SP " B o b " LF
String empty = """
"""; // the empty string (zero length)
String quote = """
"
"""; // the two characters " LF
String backslash = """
\\
"""; // the two characters \ LF
String normalStringLiteral = "test";
String code =
"""
String text = \"""
A text block inside a text block
\""";
""";
// new escape sequences
String text = """
Lorem ipsum dolor sit amet, consectetur adipiscing \
elit, sed do eiusmod tempor incididunt ut labore \
et dolore magna aliqua.\
""";
System.out.println(text);
String colors = """
red \s
green\s
blue \s
""";
System.out.println(colors);
// empty new line as first content
String emptyLine = """
test
""";
System.out.println(emptyLine.replaceAll("\n", "<LF>"));
// backslash escapes
String bs = """
\\test
""";
System.out.println(bs.replaceAll("\n", "<LF>"));
}
}

View File

@ -563,6 +563,6 @@ public record Point(int x, int y) {
}
}
]]></code>
<source-type>java 14-preview</source-type>
<source-type>java 16</source-type>
</test-code>
</test-data>

View File

@ -198,6 +198,6 @@ public class PatternMatchingInstanceof {
}
}
]]></code>
<source-type>java 14-preview</source-type>
<source-type>java 16</source-type>
</test-code>
</test-data>