rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class);
+ Assert.assertEquals(1, rangeConstructors.size());
+ Assert.assertEquals("Range", rangeConstructors.get(0).getImage());
+ JavaNode mods = rangeConstructors.get(0).getChild(0);
+ Assert.assertTrue(mods instanceof ASTModifierList);
+ Assert.assertEquals(1, mods.getNumChildren());
+ Assert.assertEquals(2, range.getDeclarations().count());
+
+ 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).getDeclaredAnnotations().count());
+ Assert.assertEquals(1, getComponent(varRec, 0).getTypeNode().descendants(ASTAnnotation.class).count());
+
+ 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 arrayRec.getComponentList().getChild(index);
+ }
+
+
+ @Test(expected = ParseException.class)
+ public void recordIsARestrictedIdentifier() {
+ java14p.parse("public class record {}");
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java
new file mode 100644
index 0000000000..cdedc88f8e
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java
@@ -0,0 +1,123 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.ast;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class TextBlockEscapeTest extends BaseParserTest {
+
+ @Test
+ public void testTextBlockContent() {
+ assertEquals("empty text block", "",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n \"\"\""));
+ assertEquals("single line text block", "winter",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n winter\"\"\""));
+ assertEquals("single line text block with LF", "winter\n",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + " winter\n"
+ + " \"\"\""));
+ assertEquals("basic text block example with html",
+ "\n"
+ + " \n"
+ + " Hello, world
\n"
+ + " \n"
+ + "\n",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + " \n"
+ + " \n"
+ + " Hello, world
\n"
+ + " \n"
+ + " \n"
+ + " \"\"\""));
+ assertEquals("text block with escapes",
+ "\r\n"
+ + " \r\n"
+ + " Hello, world
\r\n"
+ + " \r\n"
+ + "\r\n",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + " \\r\n"
+ + " \\r\n"
+ + " Hello, world
\\r\n"
+ + " \\r\n"
+ + " \\r\n"
+ + " \"\"\""));
+ assertEquals("escaped text block in inside text block",
+ "String text = \"\"\"\n"
+ + " A text block inside a text block\n"
+ + "\"\"\";\n",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + " String text = \\\"\"\"\n"
+ + " A text block inside a text block\n"
+ + " \\\"\"\";\n"
+ + " \"\"\""));
+ assertEquals("new escape: line continuation",
+ "Lorem ipsum dolor sit amet, consectetur adipiscing "
+ + "elit, sed do eiusmod tempor incididunt ut labore "
+ + "et dolore magna aliqua.",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + " Lorem ipsum dolor sit amet, consectetur adipiscing \\\n"
+ + " elit, sed do eiusmod tempor incididunt ut labore \\\n"
+ + " et dolore magna aliqua.\\\n"
+ + " \"\"\""));
+ assertEquals("new escape: space escape",
+ "red \n"
+ + "green \n"
+ + "blue \n",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + " red \\s\n"
+ + " green\\s\n"
+ + " blue \\s\n"
+ + " \"\"\""));
+ assertEquals("with crlf line endings",
+ "\n"
+ + " \n"
+ + " Hello, world
\n"
+ + " \n"
+ + "\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " Hello, world
\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \"\"\""));
+ assertEquals("with cr line endings",
+ "\n"
+ + " \n"
+ + " Hello, world
\n"
+ + " \n"
+ + "\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\r"
+ + " \r"
+ + " \r"
+ + " Hello, world
\r"
+ + " \r"
+ + " \r"
+ + " \"\"\""));
+ assertEquals("empty line directly after opening",
+ "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + " \n"
+ + " test\n"
+ + " \"\"\""));
+ assertEquals("empty crlf line directly after opening",
+ "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\r\n"
+ + " \r\n"
+ + " test\r\n"
+ + " \"\"\""));
+ assertEquals("empty line directly after opening without indentation",
+ "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\n"
+ + "\n"
+ + "test\n"
+ + "\"\"\""));
+ assertEquals("empty crlf line directly after opening without indentation",
+ "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\r\n"
+ + "\r\n"
+ + "test\r\n"
+ + "\"\"\""));
+ assertEquals("text block with backslash escape", "\\test\n",
+ ASTStringLiteral.determineTextBlockContent("\"\"\"\n \\\\test\n \"\"\""));
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/BaseClass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/BaseClass.java
new file mode 100644
index 0000000000..61c3799caa
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/BaseClass.java
@@ -0,0 +1,16 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+public class BaseClass {
+
+
+ protected void doBase() {
+ }
+
+
+ protected void doBaseWithArg(String foo) {
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass.java
new file mode 100644
index 0000000000..ed73905e7b
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass.java
@@ -0,0 +1,20 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+public class DirectSubclass extends BaseClass {
+
+
+ @Override
+ public void doBase() {
+ super.doBase();
+ }
+
+
+ @Override
+ public void doBaseWithArg(String foo) {
+ super.doBaseWithArg(foo);
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass2.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass2.java
new file mode 100644
index 0000000000..4a282aeba7
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass2.java
@@ -0,0 +1,12 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+public class DirectSubclass2 extends DirectSubclass {
+ @Override
+ public void doBase() {
+ super.doBase();
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSynchronizingSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSynchronizingSubclass.java
new file mode 100644
index 0000000000..284e0224b4
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSynchronizingSubclass.java
@@ -0,0 +1,14 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+public class DirectSynchronizingSubclass extends BaseClass {
+
+ @Override
+ protected synchronized void doBase() {
+ // overriding for synchronized
+ super.doBase();
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/ExposingSerializer.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/ExposingSerializer.java
new file mode 100644
index 0000000000..6d7de02b26
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/ExposingSerializer.java
@@ -0,0 +1,31 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import org.w3c.dom.Node;
+
+class ExposingSerializer extends Serializer {
+
+
+ ExposingSerializer(OutputStream out, String encoding) throws UnsupportedEncodingException {
+ super(out, encoding);
+ }
+
+
+ /**
+ * Overriding in order to change the access modifier from protected to public - so: not only merely calling super.
+ *
+ * Method signature in super class: protected void writeChild(nu.xom.Node arg0) throws java.io.IOException;
+ *
+ *
See: https://sourceforge.net/tracker/?func=detail&aid=1415525&group_id=56262&atid=479921
+ */
+ public void writeChild(Node node) throws IOException {
+ super.writeChild(node);
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/OtherSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/OtherSubclass.java
new file mode 100644
index 0000000000..4f8c9d23c6
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/OtherSubclass.java
@@ -0,0 +1,8 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+public class OtherSubclass extends BaseClass {
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/Serializer.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/Serializer.java
new file mode 100644
index 0000000000..614b8940d9
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/Serializer.java
@@ -0,0 +1,20 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.w3c.dom.Node;
+
+public class Serializer {
+
+ public Serializer(OutputStream out, String encoding) {
+ }
+
+ protected void writeChild(Node node) throws IOException {
+ }
+
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java
new file mode 100644
index 0000000000..050665ec8e
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java
@@ -0,0 +1,13 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod;
+
+public class TransitiveSubclass extends OtherSubclass {
+
+ @Override
+ public void doBase() {
+ super.doBase();
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/DirectSubclassInOtherPackage.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/DirectSubclassInOtherPackage.java
new file mode 100644
index 0000000000..0585d7e4dd
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/DirectSubclassInOtherPackage.java
@@ -0,0 +1,15 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod.other;
+
+import net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod.BaseClass;
+
+public class DirectSubclassInOtherPackage extends BaseClass {
+
+ @Override
+ protected void doBase() {
+ super.doBase();
+ }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/OtherClassInOtherPackage.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/OtherClassInOtherPackage.java
new file mode 100644
index 0000000000..80ec2a66d9
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/OtherClassInOtherPackage.java
@@ -0,0 +1,16 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod.other;
+
+public class OtherClassInOtherPackage {
+
+
+ public void foo() {
+ DirectSubclassInOtherPackage instance = new DirectSubclassInOtherPackage();
+ // this call is only possible, because DirectSubclassInOtherPackage makes this
+ // method available in this package as well.
+ instance.doBase();
+ }
+}
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
index 32dd65d3d0..c9befe19e5 100644
--- 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
@@ -120,7 +120,7 @@ $delim
}
- parserTest("Text block literal on non-JDK13 preview", javaVersions = !J13__PREVIEW) {
+ parserTest("Text block literal on non-JDK13 preview", javaVersions = JavaVersion.except(J13__PREVIEW, J14__PREVIEW)) {
val delim = "\"\"\""
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt
new file mode 100644
index 0000000000..959a8bc6b0
--- /dev/null
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt
@@ -0,0 +1,40 @@
+package net.sourceforge.pmd.lang.java.ast
+
+import io.kotlintest.matchers.string.shouldContain
+import net.sourceforge.pmd.lang.ast.test.shouldBe
+import net.sourceforge.pmd.lang.java.ast.JavaVersion.J14__PREVIEW
+import java.io.IOException
+
+class ASTPatternTest : ParserTestSpec({
+
+ parserTest("Test patterns only available on JDK 14 (preview)", javaVersions = !J14__PREVIEW) {
+
+ inContext(ExpressionParsingCtx) {
+ "obj instanceof Class c" should throwParseException {
+ it.message.shouldContain("Type test patterns in instanceof is a preview feature of JDK 14, you should select your language version accordingly")
+ }
+ }
+
+ }
+
+ parserTest("Test simple patterns", javaVersion = J14__PREVIEW) {
+
+ importedTypes += IOException::class.java
+ inContext(ExpressionParsingCtx) {
+
+ "obj instanceof Class c" should parseAs {
+ infixExpr(BinaryOp.INSTANCEOF) {
+ variableAccess("obj")
+ child {
+ it::getPattern shouldBe child {
+ it::getTypeNode shouldBe classType("Class")
+ it::getVarId shouldBe variableId("c")
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+})
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt
index 43218ccb46..17465ba96f 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt
@@ -7,10 +7,9 @@ package net.sourceforge.pmd.lang.java.ast
import io.kotlintest.shouldBe
import net.sourceforge.pmd.lang.ast.test.shouldBe
import net.sourceforge.pmd.lang.java.ast.BinaryOp.*
+import net.sourceforge.pmd.lang.java.ast.JavaVersion.*
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Earliest
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Latest
-import net.sourceforge.pmd.lang.java.ast.JavaVersion.J12__PREVIEW
-import net.sourceforge.pmd.lang.java.ast.JavaVersion.J13__PREVIEW
import net.sourceforge.pmd.lang.java.ast.UnaryOp.UNARY_MINUS
@@ -19,8 +18,10 @@ import net.sourceforge.pmd.lang.java.ast.UnaryOp.UNARY_MINUS
*/
class ASTSwitchExpressionTests : ParserTestSpec({
+ val switchVersions = listOf(J13__PREVIEW, J14, J14__PREVIEW)
+ val notSwitchVersions = JavaVersion.except(switchVersions)
- parserTest("No switch expr before j12 preview", javaVersions = !J12__PREVIEW) {
+ parserTest("No switch expr before j13 preview", javaVersions = notSwitchVersions) {
inContext(ExpressionParsingCtx) {
@@ -40,22 +41,8 @@ class ASTSwitchExpressionTests : ParserTestSpec({
}
- parserTest("No yield stmt before j13 preview", javaVersions = !J13__PREVIEW) {
- inContext(ExpressionParsingCtx) {
- """
- switch (day) {
- default -> {
- yield result * 4;
- }
- }
- """ shouldNot parse()
- }
-
- }
-
-
- parserTest("Simple switch expressions", javaVersions = listOf(J13__PREVIEW)) {
+ parserTest("Simple switch expressions", javaVersions = switchVersions) {
inContext(ExpressionParsingCtx) {
@@ -117,7 +104,7 @@ class ASTSwitchExpressionTests : ParserTestSpec({
- parserTest("Non-trivial labels", javaVersions = listOf(J12__PREVIEW, J13__PREVIEW)) {
+ parserTest("Non-trivial labels", javaVersions = switchVersions) {
inContext(ExpressionParsingCtx) {
@@ -150,7 +137,7 @@ class ASTSwitchExpressionTests : ParserTestSpec({
}
}
- parserTest("Switch expr precedence", javaVersions = listOf(J12__PREVIEW, J13__PREVIEW)) {
+ parserTest("Switch expr precedence", javaVersions = switchVersions) {
inContext(ExpressionParsingCtx) {
@@ -184,7 +171,7 @@ class ASTSwitchExpressionTests : ParserTestSpec({
}
- parserTest("Nested switch expressions", javaVersions = listOf(J12__PREVIEW, J13__PREVIEW)) {
+ parserTest("Nested switch expressions", javaVersions = switchVersions) {
inContext(ExpressionParsingCtx) {
@@ -244,7 +231,7 @@ class ASTSwitchExpressionTests : ParserTestSpec({
}
- parserTest("Non-fallthrough nested in fallthrough", javaVersions = listOf(J12__PREVIEW, J13__PREVIEW)) {
+ parserTest("Non-fallthrough nested in fallthrough", javaVersions = switchVersions) {
inContext(StatementParsingCtx) {
@@ -300,7 +287,7 @@ class ASTSwitchExpressionTests : ParserTestSpec({
}
- parserTest("Switch statement with non-fallthrough labels", javaVersions = listOf(J12__PREVIEW, J13__PREVIEW)) {
+ parserTest("Switch statement with non-fallthrough labels", javaVersions = switchVersions) {
inContext(StatementParsingCtx) {
"""
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
index 51db5ca5ea..3dbc19e812 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
@@ -10,6 +10,7 @@ import net.sourceforge.pmd.lang.ast.Node
import net.sourceforge.pmd.lang.ast.ParseException
import net.sourceforge.pmd.lang.ast.TokenMgrError
import net.sourceforge.pmd.lang.ast.test.*
+import net.sourceforge.pmd.lang.ast.test.shouldMatchNode
import net.sourceforge.pmd.lang.java.JavaParsingHelper
import java.beans.PropertyDescriptor
@@ -17,7 +18,10 @@ import java.beans.PropertyDescriptor
* Represents the different Java language versions.
*/
enum class JavaVersion : Comparable {
- J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11, J12, J12__PREVIEW, J13, J13__PREVIEW;
+ J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11,
+ J12,
+ J13, J13__PREVIEW,
+ J14, J14__PREVIEW;
/** Name suitable for use with e.g. [JavaParsingHelper.parse] */
val pmdName: String = name.removePrefix("J").replaceFirst("__", "-").replace('_', '.').toLowerCase()
@@ -40,6 +44,10 @@ enum class JavaVersion : Comparable {
companion object {
val Latest = values().last()
val Earliest = values().first()
+
+ fun except(vararg versions: JavaVersion) = values().toList() - versions
+ fun except(versions: List) = values().toList() - versions
+
}
}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/MultipleCaseLabels.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/MultipleCaseLabels.java
deleted file mode 100644
index b578e8c475..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/MultipleCaseLabels.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- *
- * @see JEP 325: Switch Expressions (Preview)
- */
-public class MultipleCaseLabels {
- private static final int MONDAY = 1;
- private static final int TUESDAY = 2;
- private static final int WEDNESDAY = 3;
- private static final int THURSDAY = 4;
- private static final int FRIDAY = 5;
- private static final int SATURDAY = 6;
- private static final int SUNDAY = 7;
-
-
- public static void main(String[] args) {
- int day = THURSDAY;
-
- switch (day) {
- case MONDAY, FRIDAY, SUNDAY: System.out.println(" 6"); break;
- case TUESDAY : System.out.println(" 7"); break;
- case THURSDAY, SATURDAY : System.out.println(" 8"); break;
- case WEDNESDAY : System.out.println(" 9"); break;
- }
- }
-}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressions.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressions.java
deleted file mode 100644
index 86ff120576..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressions.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- *
- * @see JEP 325: Switch Expressions (Preview)
- */
-public class SwitchExpressions {
- private static final int MONDAY = 1;
- private static final int TUESDAY = 2;
- private static final int WEDNESDAY = 3;
- private static final int THURSDAY = 4;
- private static final int FRIDAY = 5;
- private static final int SATURDAY = 6;
- private static final int SUNDAY = 7;
-
-
- public static void main(String[] args) {
- int day = FRIDAY;
-
- var numLetters = switch (day) {
- case MONDAY, FRIDAY, SUNDAY -> 6;
- case TUESDAY -> 7;
- case THURSDAY, SATURDAY -> 8;
- case WEDNESDAY -> 9;
- default -> {
- int k = day * 2;
- int result = f(k);
- break result;
- }
- };
- System.out.printf("NumLetters: %d%n", numLetters);
- }
-
- private static int f(int k) {
- return k*3;
- }
-}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java
deleted file mode 100644
index 6584e4f5df..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- *
- * @see JEP 325: Switch Expressions (Preview)
- */
-public class SwitchExpressionsBreak {
- private static final int MONDAY = 1;
- private static final int TUESDAY = 2;
- private static final int WEDNESDAY = 3;
- private static final int THURSDAY = 4;
- private static final int FRIDAY = 5;
- private static final int SATURDAY = 6;
- private static final int SUNDAY = 7;
-
- private static final int SIX = 6;
-
- public static void main(String[] args) {
- int day = FRIDAY;
-
- var numLetters = switch (day) {
- case MONDAY, FRIDAY, SUNDAY: break SwitchExpressionsBreak.SIX;
- case TUESDAY : break 7;
- case THURSDAY, SATURDAY : break 8;
- case WEDNESDAY : break 9;
- default : {
- int k = day * 2;
- int result = f(k);
- break result;
- }
- };
- System.out.printf("NumLetters: %d%n", numLetters);
- }
-
- private static int f(int k) {
- return k*3;
- }
-}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchRules.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchRules.java
deleted file mode 100644
index 844abf6bbb..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchRules.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- *
- * @see JEP 325: Switch Expressions (Preview)
- */
-public class SwitchRules {
- private static final int MONDAY = 1;
- private static final int TUESDAY = 2;
- private static final int WEDNESDAY = 3;
- private static final int THURSDAY = 4;
- private static final int FRIDAY = 5;
- private static final int SATURDAY = 6;
- private static final int SUNDAY = 7;
-
- public static void main(String[] args) {
- int day = WEDNESDAY;
-
- switch (day) {
- case MONDAY, FRIDAY, SUNDAY -> System.out.println(" 6");
- case TUESDAY -> System.out.println(" 7");
- case THURSDAY, SATURDAY -> System.out.println(" 8");
- case WEDNESDAY -> { System.out.println(" 9"); }
- default -> throw new IllegalArgumentException();
- }
- }
-}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java13/TextBlocks.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java13/TextBlocks.java
new file mode 100644
index 0000000000..78a6d111c3
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java13/TextBlocks.java
@@ -0,0 +1,55 @@
+/**
+ * @see JEP 355: Text Blocks (Preview)
+ */
+public class TextBlocks {
+
+ public static void main(String[] args) {
+ String html = """
+
+
+ Hello, world
+
+
+ """;
+
+ System.out.println(html);
+
+ 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
+ \""";
+ """;
+ }
+}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java
new file mode 100644
index 0000000000..ac3fe4fd46
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java
@@ -0,0 +1,10 @@
+/**
+ * @see JEP 359: Records (Preview)
+ */
+public record Point(int x, int y) {
+
+ public static void main(String[] args) {
+ Point p = new Point(1, 2);
+ System.out.println("p = " + p);
+ }
+}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java
new file mode 100644
index 0000000000..2368b2ae7c
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java
@@ -0,0 +1,61 @@
+import java.io.IOException;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * @see JEP 359: Records (Preview)
+ */
+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() {
+ public void foo() { }
+ public Type bar() { return null; }
+ public static void baz() {
+ EmptyRec 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 {
+
+ }
+}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java
new file mode 100644
index 0000000000..5ff553185f
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java
@@ -0,0 +1,113 @@
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+
+/**
+ * @see JEP 368: Text Blocks (Second Preview)
+ */
+public class TextBlocks {
+
+
+ public static void main(String[] args) throws Exception {
+ // note: there is trailing whitespace!!
+ String html = """
+
+
+ Hello, world
+
+
+ """;
+ 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 = """
+ \r
+ \r
+ Hello, world
\r
+ \r
+ \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", ""));
+
+ // backslash escapes
+ String bs = """
+ \\test
+ """;
+ System.out.println(bs.replaceAll("\n", ""));
+ }
+}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml
index b242777cda..dc0889ee2e 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml
@@ -3,10 +3,9 @@
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
+
-
+ call super
1
+
-
+ call super with same argument
1
+
-
+ call super with different argument
0
+
-
+ call super with different argument 2
0
+
-
+ call super with different argument 3
0
+
-
+ call super with inverted arguments
0
+
-
+ return value of super
1
+
-
+ return value of super with argument
1
+
-
+ return value of super after adding a string
0
+
-
+ do not crash on abstract methods
0
+
-
+ do not crash on interfaces
0
+
-
+ do not crash on empty returns
0
+
-
+ do not crash on super
0
+
-
+ call super with different argument 4
0
+
-
+ adding final is OK
0
+
-
+ adding synchronized is OK, see sf-bug #423
0
+
-
+ Constructors are OK
0
+
-
+ Should ignore clone implementation ( see bug 1522517)
0
+
-
+ clone method with arguments should not be ignored
1
-
-
-
-
+
+
+ False +: Overriding method merely calls super (see bug 1415525)
0
-
- Method signature in super class: protected void writeChild(nu.xom.Node arg0) throws java.io.IOException;
+ *
+ * See: https://sourceforge.net/tracker/?func=detail&aid=1415525&group_id=56262&atid=479921
+ */
+ public void writeChild(Node node) throws IOException {
+ super.writeChild(node);
+ }
}
]]>
+
-
-
-
+ [ 1977230 ] false positive: UselessOverridingMethod
0
-
-
-
-
-
+
+
+ [ 2142986 ] UselessOverridingMethod doesn't consider annotations, ignoreAnnotations property set to true
true
1
-
-
-
-
-
+
+
+ [ 2142986 ] UselessOverridingMethod doesn't consider annotations
0
-
-
-
-
-
+
+
+ [ 2142986 ] UselessOverridingMethod doesn't consider annotations, @Override only
1
-
+
-
+ ClassCastException in statement cast
0
comparator = new Comparator() {
+ public void method() {
+ @SuppressWarnings("unused")
+ final Comparator comparator = new Comparator() {
- @Override
- public int compare(@Nonnull Long o1, @Nonnull Long o2) {
- return 0;
- }
- };
- }
+ @Override
+ public int compare(@Nonnull Long o1, @Nonnull Long o2) {
+ return 0;
+ }
+ };
+ }
}
]]>
+
+
+ [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct
+ 0
+
+
+
+
+ [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct but changing arguments
+ 0
+
+
+
+
+ [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct different package, same visibility
+ 0
+
+
+
+
+ [java] UselessOverridingMethod false positive when elevating access modifier #911 - transitive
+ 0
+
+
+
+
+ [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct2
+ 1
+ 5
+
+
+
+
+ Make sure, overriding to add synchronized is Ok, see sf-bug #423
+ 0
+
+
\ No newline at end of file
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml
index 5291a2822a..1d23d6f199 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml
@@ -3,36 +3,61 @@
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
+
-
- 1
+ null check after method invocation with conditional AND and !=
+ 4
+ 3,4,6,7
+
+ The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException
+ The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException
+ The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException
+ The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException
+
+
-
- 1
+ null check after nested method invocation
+ 4
+ 3,4,6,7
+
+ The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException
+ The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException
+ The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException
+ The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException
+
+
-
+ null check before nested method invocation
0
+
-
+ 1610730: null check after method invocation with conditional OR and ==
1
+ 3
+
+ The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException
+
+
-
+ 3372128: False positive: ArrayIsStoredDirectly
0
+
#977 MisplacedNullCheck makes false positives
0
@@ -81,8 +109,68 @@ public class Test {
if ((value != null && !value.equals(oldValue)) || value == null) {
// Do something
}
+
+ if ((value == null || !value.equals(oldValue)) && value != null) {}
}
}
]]>
+
+
+ #2242 False-positive MisplacedNullCheck reported (1)
+ 0
+
+
+
+
+ #2242 False-positive MisplacedNullCheck reported (2)
+ 0
+
+
+
+
+ False-positive/negative with multiple conditions
+ 2
+ 7,8
+
+ The null check here is misplaced; if the variable 'attributes' is null there will be a NullPointerException
+ The null check here is misplaced; if the variable 'attributes' is null there will be a NullPointerException
+
+ attributes) {
+ boolean isStereotype = annotationType.equals("javax.inject.Named");
+ if (isStereotype && attributes != null && attributes.containsKey("value")) {}
+ if (isStereotype || attributes == null || attributes.containsKey("value")) {}
+
+ if (isStereotype && attributes.containsKey("value") && attributes != null) {}
+ if (isStereotype || attributes.containsKey("value") || attributes == null) {}
+ }
+}
+ ]]>
+
diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt
index 651d2988d6..2f7418ab28 100644
--- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt
+++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt
@@ -51,7 +51,8 @@ abstract class BaseParsingHelper, T : RootNode
*/
fun getVersion(version: String?): LanguageVersion {
val language = LanguageRegistry.getLanguage(langName)
- return if (version == null) language.defaultVersion else language.getVersion(version)
+ return if (version == null) language.defaultVersion
+ else language.getVersion(version) ?: throw AssertionError("Unsupported version $version for language $language")
}
val defaultVersion: LanguageVersion
diff --git a/pom.xml b/pom.xml
index 10bd52d9e3..5812d7ef4e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -629,7 +629,7 @@
org.ow2.asm
asm
- 7.1
+ 7.3.1
net.sourceforge.pmd