From bc19d2cc406ab626f75a1150baeaab07f0b909fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 1 Apr 2022 18:56:16 +0200 Subject: [PATCH] [java] Improve module grammar Type names in "provides" directives are disambiguated like any other type name. ASTName is made redundant and removed for good. --- pmd-java/etc/grammar/Java.jjt | 59 +++++++++------ .../pmd/lang/java/ast/ASTCompilationUnit.java | 10 ++- .../lang/java/ast/ASTModuleDeclaration.java | 30 +++++++- .../pmd/lang/java/ast/ASTModuleDirective.java | 73 ++++++++++--------- .../java/ast/ASTModuleExportsDirective.java | 39 ++++++++++ .../pmd/lang/java/ast/ASTModuleName.java | 19 +++++ .../java/ast/ASTModuleOpensDirective.java | 40 ++++++++++ .../java/ast/ASTModuleProvidesDirective.java | 39 ++++++++++ .../java/ast/ASTModuleRequiresDirective.java | 57 +++++++++++++++ .../lang/java/ast/ASTModuleUsesDirective.java | 26 +++++++ .../pmd/lang/java/ast/ASTName.java | 46 ------------ .../lang/java/ast/ASTPackageDeclaration.java | 3 +- .../pmd/lang/java/ast/ASTYieldStatement.java | 9 --- .../AbstractPackageNameModuleDirective.java | 26 +++++++ .../rule/bestpractices/LooseCouplingRule.java | 2 + .../lang/java/types/ast/LazyTypeResolver.java | 6 -- .../java/ast/ASTModuleDeclarationTest.java | 58 ++------------- .../pmd/lang/java/ast/JDKVersionTest.java | 32 +++++--- .../pmd/lang/java/ast/Java9TreeDumpTest.java | 34 +++++++++ .../pmd/lang/java/ast/SimpleNodeTest.java | 39 ---------- .../lang/java/ast/TypeDisambiguationTest.kt | 26 +++++++ .../{ => java9}/jdk9_anonymous_diamond.java | 0 .../{ => java9}/jdk9_invalid_identifier.java | 0 .../{ => java9}/jdk9_module_info.java | 3 +- .../java9/jdk9_module_info.txt | 20 +++++ .../jdk9_module_info_with_annot.java | 0 .../java9/jdk9_module_info_with_annot.txt | 10 +++ .../jdk9_private_interface_methods.java | 0 .../{ => java9}/jdk9_try_with_resources.java | 4 + 29 files changed, 482 insertions(+), 228 deletions(-) create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleExportsDirective.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleOpensDirective.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleProvidesDirective.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleRequiresDirective.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleUsesDirective.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractPackageNameModuleDirective.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java9TreeDumpTest.java rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{ => java9}/jdk9_anonymous_diamond.java (100%) rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{ => java9}/jdk9_invalid_identifier.java (100%) rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{ => java9}/jdk9_module_info.java (80%) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info.txt rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{ => java9}/jdk9_module_info_with_annot.java (100%) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info_with_annot.txt rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{ => java9}/jdk9_private_interface_methods.java (100%) rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{ => java9}/jdk9_try_with_resources.java (81%) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 5a3fc90bed..0563a698e4 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,9 @@ /** + * Improve module grammar. + * Type names in "provides" directives are disambiguated like any other type name. + * ASTName is made redundant and removed for good. + * Clément Fournier 03/2022 + *==================================================================== * Support "JEP 420: Pattern Matching for switch (Second Preview)" for Java 18 Preview * There were no grammar changes between 18-preview and 17-preview * Remove support for Java 16 preview language features @@ -2734,40 +2739,34 @@ void DefaultValue(): } void ModuleDeclaration(): +{} { - StringBuilder s = new StringBuilder(); - JavaccToken t; -} -{ - ( Annotation() )* [LOOKAHEAD({isKeyword("open")}) {jjtThis.setOpen(true);}] LOOKAHEAD({isKeyword("module")}) - t= { s.append(t.getImage()); } - ( "." t= { s.append('.').append(t.getImage()); } )* { jjtThis.setImage(s.toString()); } + AnnotationList() + [LOOKAHEAD({isKeyword("open")}) {jjtThis.setOpen(true);}] + LOOKAHEAD({isKeyword("module")}) + ModuleName() "{" (ModuleDirective())* "}" } -void ModuleDirective(): -{} +void ModuleDirective() #void: +{String packageName;} { - ( LOOKAHEAD({isKeyword("requires")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.REQUIRES); } - (LOOKAHEAD({isKeyword("transitive")}) { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.TRANSITIVE); } | - "static" { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.STATIC); } )? - ModuleName() ";" ) - | ( LOOKAHEAD({isKeyword("exports")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.EXPORTS); } Name() [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())*] ";" ) - | ( LOOKAHEAD({isKeyword("opens")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.OPENS); } Name() [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())*] ";" ) - | ( LOOKAHEAD({isKeyword("uses")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.USES); } Name() ";" ) - | ( LOOKAHEAD({isKeyword("provides")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.PROVIDES); } Name() LOOKAHEAD({isKeyword("with")}) Name() ("," Name() )* ";" ) + ( LOOKAHEAD({isKeyword("requires")}) + [ + LOOKAHEAD({isKeyword("transitive")}) { jjtThis.setTransitive(); } + | "static" { jjtThis.setStatic(); } + ] + ModuleName() ";" ) #ModuleRequiresDirective + | ( LOOKAHEAD({isKeyword("exports")}) packageName=VoidNameNoLookahead() {jjtThis.setPackageName(packageName);} [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())* ] ";" ) #ModuleExportsDirective + | ( LOOKAHEAD({isKeyword("opens")}) packageName=VoidNameNoLookahead() {jjtThis.setPackageName(packageName);} [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())* ] ";" ) #ModuleOpensDirective + | ( LOOKAHEAD({isKeyword("uses")}) packageName=VoidNameNoLookahead() {jjtThis.setPackageName(packageName);} ";" ) #ModuleUsesDirective + | ( LOOKAHEAD({isKeyword("provides")}) ClassName() LOOKAHEAD({isKeyword("with")}) ClassName() ("," ClassName() )* ";" ) #ModuleProvidesDirective } void ModuleName(): { String name; } { - name=VoidName() { jjtThis.setImage(name); } -} - -void Name(): -{ String name; } -{ - name=VoidName() { jjtThis.setImage(name); } + name=VoidNameNoLookahead() { jjtThis.setImage(name); } } void AmbiguousName(): @@ -2793,6 +2792,18 @@ String VoidName() #void: {return s.toString();} } + +String VoidNameNoLookahead() #void: +{ + StringBuilder s = new StringBuilder(); + JavaccToken t; +} +{ + t= { s.append(t.getImage()); } + ( "." t= { s.append('.').append(t.getImage()); } )* + {return s.toString();} +} + // Produces a ClassOrInterfaceType, possibly with an ambiguous LHS void ClassName() #void: {} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java index c50bb27f76..9d0f3987f4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java @@ -73,8 +73,7 @@ public final class ASTCompilationUnit extends AbstractJavaTypeNode implements Ja * Returns the package name of this compilation unit. If there is no * package declaration, then returns the empty string. */ - @NonNull - public String getPackageName() { + public @NonNull String getPackageName() { ASTPackageDeclaration pack = getPackageDeclaration(); return pack == null ? "" : pack.getName(); } @@ -88,6 +87,13 @@ public final class ASTCompilationUnit extends AbstractJavaTypeNode implements Ja return children(ASTAnyTypeDeclaration.class); } + /** + * Returns the module declaration, if this is a modular compilation unit. + */ + public @Nullable ASTModuleDeclaration getModuleDeclaration() { + return firstChild(ASTModuleDeclaration.class); + } + @Override public @NonNull JSymbolTable getSymbolTable() { assert symbolTable != null : "Symbol table wasn't set"; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java index 074065a1e0..047d20d99d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java @@ -4,7 +4,21 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTModuleDeclaration extends AbstractJavaNode { +import net.sourceforge.pmd.lang.ast.NodeStream; + +/** + * A module declaration. This is found at the top-level of a + * {@linkplain ASTCompilationUnit modular compilation unit}. + * + *
+ *
+ * ModuleDeclaration ::= {@linkplain ASTModifierList AnnotationList} "open"?
+ *                       "module" {@linkplain ASTModuleName ModuleName}
+ *                       "{" {@linkplain ASTModuleDirective ModuleDirective}* "}"
+ *
+ * 
+ */ +public final class ASTModuleDeclaration extends AbstractJavaNode implements Annotatable { private boolean open; @@ -18,6 +32,20 @@ public final class ASTModuleDeclaration extends AbstractJavaNode { return visitor.visit(this, data); } + /** + * Returns the name of the declared module. Module names look + * like package names, eg {@code java.base}. + */ + public String getName() { + return firstChild(ASTModuleName.class).getName(); + } + + /** + * Returns a stream with all directives declared by the module. + */ + public NodeStream getDirectives() { + return children(ASTModuleDirective.class); + } void setOpen(boolean open) { this.open = open; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java index 047f9ff964..41f6cc277d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java @@ -4,44 +4,47 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTModuleDirective extends AbstractJavaNode { +import net.sourceforge.pmd.lang.rule.xpath.NoAttribute; + +/** + * A directive of a {@linkplain ASTModuleDeclaration module declaration}. + * Implementations provide more specific attributes. + * + *
+ *
+ * ModuleDirective ::= {@linkplain ASTModuleRequiresDirective ModuleRequiresDirective}
+ *                   | {@linkplain ASTModuleOpensDirective ModuleOpensDirective}
+ *                   | {@linkplain ASTModuleExportsDirective ModuleExportsDirective}
+ *                   | {@linkplain ASTModuleProvidesDirective ModuleProvidesDirective}
+ *                   | {@linkplain ASTModuleUsesDirective ModuleUsesDirective}
+ *
+ * 
+ */ +public abstract class ASTModuleDirective extends AbstractJavaNode { + + private final DirectiveType type; + + + ASTModuleDirective(int id, DirectiveType type) { + super(id); + this.type = type; + } + + /** + * Returns the kind of the directive. + */ + @NoAttribute + public DirectiveType getType() { + return type; + } + + /** + * Kind of a module directive. Specific kinds are represented by + * specific subclasses. + */ public enum DirectiveType { REQUIRES, EXPORTS, OPENS, USES, PROVIDES } - public enum RequiresModifier { - STATIC, TRANSITIVE - } - - private DirectiveType type; - - private RequiresModifier requiresModifier; - - ASTModuleDirective(int id) { - super(id); - } - - - @Override - protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); - } - - - void setType(DirectiveType type) { - this.type = type; - } - - public String getType() { - return String.valueOf(type); - } - - void setRequiresModifier(RequiresModifier requiresModifier) { - this.requiresModifier = requiresModifier; - } - - public String getRequiresModifier() { - return requiresModifier == null ? null : requiresModifier.name(); - } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleExportsDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleExportsDirective.java new file mode 100644 index 0000000000..ab2fe93fed --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleExportsDirective.java @@ -0,0 +1,39 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import net.sourceforge.pmd.lang.ast.NodeStream; + +/** + * An "exports" directive of a {@linkplain ASTModuleDeclaration module declaration}. + * + *
+ *
+ * ModuleExportsDirective ::=
+ *     "exports" <PACKAGE_NAME>
+ *     ( "to" {@linkplain ASTModuleName ModuleName} ( "," {@linkplain ASTModuleName ModuleName})* )?
+ *     ";"
+ *
+ * 
+ */ +public final class ASTModuleExportsDirective extends AbstractPackageNameModuleDirective { + + ASTModuleExportsDirective(int id) { + super(id, DirectiveType.EXPORTS); + } + + @Override + protected R acceptVisitor(JavaVisitor visitor, P data) { + return visitor.visit(this, data); + } + + /** + * Returns a stream of the module names that are found after the "to" keyword. + * May be empty + */ + public NodeStream getTargetModules() { + return children(ASTModuleName.class); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java index dfb9acc73f..69a24d555e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java @@ -4,6 +4,10 @@ package net.sourceforge.pmd.lang.java.ast; +/** + * The name of a module. Module names look like package names, eg + * {@code java.base}. + */ public final class ASTModuleName extends AbstractJavaNode { ASTModuleName(int id) { @@ -15,4 +19,19 @@ public final class ASTModuleName extends AbstractJavaNode { public R acceptVisitor(JavaVisitor visitor, P data) { return visitor.visit(this, data); } + + @Override + @Deprecated + public String getImage() { + return null; + } + + /** + * Returns the name of the declared module. Module names look + * like package names, eg {@code java.base}. + */ + public String getName() { + return super.getImage(); + } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleOpensDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleOpensDirective.java new file mode 100644 index 0000000000..b575c83de9 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleOpensDirective.java @@ -0,0 +1,40 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import net.sourceforge.pmd.lang.ast.NodeStream; + +/** + * An "opens" directive of a {@linkplain ASTModuleDeclaration module declaration}. + * + *
+ *
+ * ModuleOpensDirective ::=
+ *     "opens" <PACKAGE_NAME>
+ *     ( "to" {@linkplain ASTModuleName ModuleName} ( "," {@linkplain ASTModuleName ModuleName})* )?
+ *     ";"
+ *
+ * 
+ */ +public final class ASTModuleOpensDirective extends AbstractPackageNameModuleDirective { + + ASTModuleOpensDirective(int id) { + super(id, DirectiveType.OPENS); + } + + @Override + protected R acceptVisitor(JavaVisitor visitor, P data) { + return visitor.visit(this, data); + } + + /** + * Returns a stream of the module names that are found after the "to" keyword. + * May be empty + */ + public NodeStream getTargetModules() { + return children(ASTModuleName.class); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleProvidesDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleProvidesDirective.java new file mode 100644 index 0000000000..8c833733bc --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleProvidesDirective.java @@ -0,0 +1,39 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import net.sourceforge.pmd.lang.ast.NodeStream; + +/** + * A "provides" directive of a {@linkplain ASTModuleDeclaration module declaration}. + * + *
+ *
+ * ModuleProvidesDirective ::=
+ *     "provides" {@linkplain ASTClassOrInterfaceType ClassType}
+ *     "with" {@linkplain ASTClassOrInterfaceType ClassType} ( "," {@linkplain ASTClassOrInterfaceType ClassType} )*
+ *     ";"
+ *
+ * 
+ */ +public final class ASTModuleProvidesDirective extends ASTModuleDirective { + + ASTModuleProvidesDirective(int id) { + super(id, DirectiveType.PROVIDES); + } + + @Override + protected R acceptVisitor(JavaVisitor visitor, P data) { + return visitor.visit(this, data); + } + + public ASTClassOrInterfaceType getProvidedInterface() { + return firstChild(ASTClassOrInterfaceType.class); + } + + public NodeStream getImplementations() { + return children(ASTClassOrInterfaceType.class).drop(1); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleRequiresDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleRequiresDirective.java new file mode 100644 index 0000000000..add47fa902 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleRequiresDirective.java @@ -0,0 +1,57 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import java.util.Objects; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * A "requires" directive of a {@linkplain ASTModuleDeclaration module declaration}. + * + *
+ *
+ * ModuleRequiresDirective ::=
+ *     "requires" ( "transitive" | "static" )? {@linkplain ASTModuleName ModuleName} ";"
+ *
+ * 
+ */ +public final class ASTModuleRequiresDirective extends ASTModuleDirective { + + private boolean isStatic; + private boolean isTransitive; + + ASTModuleRequiresDirective(int id) { + super(id, DirectiveType.REQUIRES); + } + + @Override + protected R acceptVisitor(JavaVisitor visitor, P data) { + return visitor.visit(this, data); + } + + /** + * Returns the name of the required module. + */ + public @NonNull ASTModuleName getRequiredModule() { + return Objects.requireNonNull(firstChild(ASTModuleName.class)); + } + + public boolean isStatic() { + return isStatic; + } + + public boolean isTransitive() { + return isTransitive; + } + + void setTransitive() { + isTransitive = true; + } + + void setStatic() { + isStatic = true; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleUsesDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleUsesDirective.java new file mode 100644 index 0000000000..c7557f6e4a --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleUsesDirective.java @@ -0,0 +1,26 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +/** + * A "uses" directive of a {@linkplain ASTModuleDeclaration module declaration}. + * + *
+ *
+ * ModuleUsesDirective ::= "uses" <PACKAGE_NAME> ";"
+ *
+ * 
+ */ +public final class ASTModuleUsesDirective extends AbstractPackageNameModuleDirective { + + ASTModuleUsesDirective(int id) { + super(id, DirectiveType.USES); + } + + @Override + protected R acceptVisitor(JavaVisitor visitor, P data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java deleted file mode 100644 index 55e5e9daf0..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.symboltable.NameDeclaration; - -public class ASTName extends AbstractJavaTypeNode { - - private NameDeclaration nd; - - - /** - * Constructor for a synthetic node. - * @param image Image of the new node - */ - @InternalApi - @Deprecated - public ASTName(String image, AbstractJavaNode parent) { - super(JavaParserImplTreeConstants.JJTNAME); - setImage(image); - setParent(parent); - } - - ASTName(int id) { - super(id); - } - - @InternalApi - @Deprecated - public void setNameDeclaration(NameDeclaration nd) { - this.nd = nd; - } - - public NameDeclaration getNameDeclaration() { - return this.nd; - } - - - @Override - protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java index 2f81ccb2ae..046101921e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java @@ -6,8 +6,7 @@ package net.sourceforge.pmd.lang.java.ast; /** * Package declaration at the top of a {@linkplain ASTCompilationUnit source file}. - * Since 7.0, there is no {@linkplain ASTName Name} node anymore. Use - * {@link #getName()} instead. + * Since 7.0, there is no Name node anymore. Use {@link #getName()} instead. * * *
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java
index 657e0cd703..16fdd17582 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java
@@ -30,15 +30,6 @@ public class ASTYieldStatement extends AbstractStatement {
         return visitor.visit(this, data);
     }
 
-    @Override
-    public String getImage() {
-        String result = super.getImage();
-        if (result == null && hasDescendantOfType(ASTName.class)) {
-            result = getFirstDescendantOfType(ASTName.class).getImage();
-        }
-        return result;
-    }
-
 
     /** Returns the yielded expression. */
     public ASTExpression getExpr() {
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractPackageNameModuleDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractPackageNameModuleDirective.java
new file mode 100644
index 0000000000..6bf5a78bf3
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractPackageNameModuleDirective.java
@@ -0,0 +1,26 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.ast;
+
+public abstract class AbstractPackageNameModuleDirective extends ASTModuleDirective {
+
+    AbstractPackageNameModuleDirective(int id, DirectiveType type) {
+        super(id, type);
+    }
+
+    public final String getPackageName() {
+        return super.getImage();
+    }
+
+    @Override
+    @Deprecated
+    public final String getImage() {
+        return null;
+    }
+
+    final void setPackageName(String name) {
+        super.setImage(name);
+    }
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java
index 3024edaa48..78f4812477 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java
@@ -18,6 +18,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
 import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
 import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTModuleProvidesDirective;
 import net.sourceforge.pmd.lang.java.ast.ASTSuperExpression;
 import net.sourceforge.pmd.lang.java.ast.ASTThisExpression;
 import net.sourceforge.pmd.lang.java.ast.ASTTypeExpression;
@@ -62,6 +63,7 @@ public class LooseCouplingRule extends AbstractJavaRulechainRule {
             || parent instanceof ASTExtendsList          // extends AbstractMap<...>
             || parent instanceof ASTThisExpression       // Enclosing.this
             || parent instanceof ASTSuperExpression      // Enclosing.super
+            || parent instanceof ASTModuleProvidesDirective  // provides  with 
             || parent instanceof ASTArrayType && parent.getParent() instanceof ASTArrayAllocation;
     }
 
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java
index 9fa259f112..d813bba861 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java
@@ -42,7 +42,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
 import net.sourceforge.pmd.lang.java.ast.ASTLambdaParameter;
 import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
 import net.sourceforge.pmd.lang.java.ast.ASTMethodReference;
-import net.sourceforge.pmd.lang.java.ast.ASTName;
 import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;
 import net.sourceforge.pmd.lang.java.ast.ASTNumericLiteral;
 import net.sourceforge.pmd.lang.java.ast.ASTPattern;
@@ -152,11 +151,6 @@ public final class LazyTypeResolver extends JavaVisitorBase directives = module.children(ASTModuleDirective.class).toList();
-        assertEquals(7, directives.size());
-
-        // requires com.example.foo.http;
-        assertEquals(ASTModuleDirective.DirectiveType.REQUIRES.name(), directives.get(0).getType());
-        assertNull(directives.get(0).getRequiresModifier());
-        assertEquals("com.example.foo.http", directives.get(0).getFirstChildOfType(ASTModuleName.class).getImage());
-
-        // requires java.logging;
-        assertEquals(ASTModuleDirective.DirectiveType.REQUIRES.name(), directives.get(1).getType());
-        assertNull(directives.get(1).getRequiresModifier());
-        assertEquals("java.logging", directives.get(1).getFirstChildOfType(ASTModuleName.class).getImage());
-
-        // requires transitive com.example.foo.network;
-        assertEquals(ASTModuleDirective.DirectiveType.REQUIRES.name(), directives.get(2).getType());
-        assertEquals(ASTModuleDirective.RequiresModifier.TRANSITIVE.name(), directives.get(2).getRequiresModifier());
-        assertEquals("com.example.foo.network", directives.get(2).getFirstChildOfType(ASTModuleName.class).getImage());
-
-        // exports com.example.foo.bar;
-        assertEquals(ASTModuleDirective.DirectiveType.EXPORTS.name(), directives.get(3).getType());
-        assertNull(directives.get(3).getRequiresModifier());
-        assertEquals("com.example.foo.bar", directives.get(3).getFirstChildOfType(ASTName.class).getImage());
-
-        // exports com.example.foo.internal to com.example.foo.probe;
-        assertEquals(ASTModuleDirective.DirectiveType.EXPORTS.name(), directives.get(4).getType());
-        assertNull(directives.get(4).getRequiresModifier());
-        assertEquals("com.example.foo.internal", directives.get(4).getFirstChildOfType(ASTName.class).getImage());
-        assertEquals("com.example.foo.probe", directives.get(4).getFirstChildOfType(ASTModuleName.class).getImage());
-
-        // uses com.example.foo.spi.Intf;
-        assertEquals(ASTModuleDirective.DirectiveType.USES.name(), directives.get(5).getType());
-        assertNull(directives.get(5).getRequiresModifier());
-        assertEquals("com.example.foo.spi.Intf", directives.get(5).getFirstChildOfType(ASTName.class).getImage());
-
-        // provides com.example.foo.spi.Intf with com.example.foo.Impl;
-        assertEquals(ASTModuleDirective.DirectiveType.PROVIDES.name(), directives.get(6).getType());
-        assertNull(directives.get(6).getRequiresModifier());
-        assertEquals("com.example.foo.spi.Intf", directives.get(6).getFirstChildOfType(ASTName.class).getImage());
-        assertEquals("com.example.foo.Impl", directives.get(6).findChildrenOfType(ASTName.class).get(1).getImage());
+    public void testAnnotatable() {
+        ASTCompilationUnit root = java9.parse("@A @B module foo { } ");
+        ASTModuleDeclaration mod = root.getModuleDeclaration();
+        assertTrue(mod.isAnnotationPresent("A"));
+        assertTrue(mod.isAnnotationPresent("B"));
     }
 
 }
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java
index 832f51e87c..7a22b1c5d6 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java
@@ -11,12 +11,15 @@ import static org.junit.Assert.fail;
 
 import java.util.List;
 
+import org.checkerframework.checker.nullness.qual.NonNull;
 import org.junit.Test;
 
 import net.sourceforge.pmd.lang.ast.ParseException;
+import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
+import net.sourceforge.pmd.lang.java.BaseJavaTreeDumpTest;
 import net.sourceforge.pmd.lang.java.JavaParsingHelper;
 
-public class JDKVersionTest {
+public class JDKVersionTest extends BaseJavaTreeDumpTest {
 
     private final JavaParsingHelper java3 = JavaParsingHelper.DEFAULT
         .withDefaultVersion("1.3")
@@ -210,7 +213,7 @@ public class JDKVersionTest {
 
     @Test(expected = ParseException.class)
     public final void jdk9PrivateInterfaceMethodsInJava18() {
-        java8.parseResource("jdk9_private_interface_methods.java");
+        java8.parseResource("java9/jdk9_private_interface_methods.java");
     }
 
     @Test
@@ -225,52 +228,52 @@ public class JDKVersionTest {
 
     @Test
     public final void jdk9PrivateInterfaceMethods() {
-        java9.parseResource("jdk9_private_interface_methods.java");
+        java9.parseResource("java9/jdk9_private_interface_methods.java");
     }
 
     @Test
     public final void jdk9InvalidIdentifierInJava18() {
-        java8.parseResource("jdk9_invalid_identifier.java");
+        java8.parseResource("java9/jdk9_invalid_identifier.java");
     }
 
     @Test(expected = ParseException.class)
     public final void jdk9InvalidIdentifier() {
-        java9.parseResource("jdk9_invalid_identifier.java");
+        java9.parseResource("java9/jdk9_invalid_identifier.java");
     }
 
     @Test(expected = ParseException.class)
     public final void jdk9AnonymousDiamondInJava8() {
-        java8.parseResource("jdk9_anonymous_diamond.java");
+        java8.parseResource("java9/jdk9_anonymous_diamond.java");
     }
 
     @Test
     public final void jdk9AnonymousDiamond() {
-        java9.parseResource("jdk9_anonymous_diamond.java");
+        java9.parseResource("java9/jdk9_anonymous_diamond.java");
     }
 
     @Test(expected = ParseException.class)
     public final void jdk9ModuleInfoInJava8() {
-        java8.parseResource("jdk9_module_info.java");
+        java8.parseResource("java9/jdk9_module_info.java");
     }
 
     @Test
     public final void jdk9ModuleInfo() {
-        java9.parseResource("jdk9_module_info.java");
+        java9.parseResource("java9/jdk9_module_info.java");
     }
 
     @Test
     public void testAnnotatedModule() {
-        java9.parseResource("jdk9_module_info_with_annot.java");
+        java9.parseResource("java9/jdk9_module_info_with_annot.java");
     }
 
     @Test(expected = ParseException.class)
     public final void jdk9TryWithResourcesInJava8() {
-        java8.parseResource("jdk9_try_with_resources.java");
+        java8.parseResource("java9/jdk9_try_with_resources.java");
     }
 
     @Test
     public final void jdk9TryWithResources() {
-        java9.parseResource("jdk9_try_with_resources.java");
+        java9.parseResource("java9/jdk9_try_with_resources.java");
     }
 
     @Test
@@ -292,4 +295,9 @@ public class JDKVersionTest {
             assertTrue(e.getMessage().startsWith("Line 19"));
         }
     }
+
+    @Override
+    public @NonNull BaseParsingHelper getParser() {
+        return java9;
+    }
 }
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java9TreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java9TreeDumpTest.java
new file mode 100644
index 0000000000..26f6eeee4e
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java9TreeDumpTest.java
@@ -0,0 +1,34 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.ast;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.junit.Test;
+
+import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
+import net.sourceforge.pmd.lang.java.BaseJavaTreeDumpTest;
+import net.sourceforge.pmd.lang.java.JavaParsingHelper;
+
+public class Java9TreeDumpTest extends BaseJavaTreeDumpTest {
+
+    private final JavaParsingHelper java9 = JavaParsingHelper.DEFAULT
+        .withDefaultVersion("9")
+        .withResourceContext(Java9TreeDumpTest.class, "jdkversiontests/java9");
+
+    @Test
+    public void testModule() {
+        doTest("jdk9_module_info");
+    }
+
+    @Test
+    public void testAnnotatedModule() {
+        doTest("jdk9_module_info_with_annot");
+    }
+
+    @Override
+    public @NonNull BaseParsingHelper getParser() {
+        return java9;
+    }
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java
index f13a357ae9..1a0d051952 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java
@@ -6,8 +6,6 @@ package net.sourceforge.pmd.lang.java.ast;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import java.util.List;
@@ -66,27 +64,6 @@ public class SimpleNodeTest extends BaseParserTest {
         assertFalse(ucd.getChild(0) instanceof ASTImplementsList);
     }
 
-    @Test
-    public void testColumnsOnQualifiedName() {
-        for (Node node : java.getNodes(ASTName.class, QUALIFIED_NAME)) {
-            if (node.getImage().equals("java.io.File")) {
-                TestUtilsKt.assertPosition(node, 1, 8, 1, 20);
-            }
-        }
-    }
-
-    @Test
-    public void testLineNumbersForNameSplitOverTwoLines() {
-        for (Node node : java.getNodes(ASTName.class, BROKEN_LINE_IN_NAME)) {
-            if (node.getImage().equals("java.io.File")) {
-                TestUtilsKt.assertPosition(node, 1, 8, 2, 5);
-            }
-            if (node.getImage().equals("Foo")) {
-                TestUtilsKt.assertPosition(node, 2, 15, 2, 19);
-            }
-        }
-    }
-
     //    @Test
     //    public void testLineNumbersAreSetOnAllSiblings() {
     //        for (ASTBlock b : java.getNodes(ASTBlock.class, LINE_NUMBERS_ON_SIBLINGS)) {
@@ -172,22 +149,6 @@ public class SimpleNodeTest extends BaseParserTest {
     //        assertEquals(x2, n);
     //    }
 
-    @Test
-    public void testParentMethods() {
-        ASTCompilationUnit u = java.parse(TEST1);
-
-        ASTMethodDeclarator d = u.getFirstDescendantOfType(ASTMethodDeclarator.class);
-        assertSame("getFirstParentOfType ASTMethodDeclaration", d.getParent(),
-                d.getFirstParentOfType(ASTMethodDeclaration.class));
-        assertNull("getFirstParentOfType ASTName", d.getFirstParentOfType(ASTName.class));
-
-        assertSame("getNthParent 1", d.getParent(), d.getNthParent(1));
-        assertSame("getNthParent 2", d.getParent().getParent(), d.getNthParent(2));
-        assertSame("getNthParent 6", u, d.getNthParent(6));
-        assertNull("getNthParent 7", d.getNthParent(7));
-        assertNull("getNthParent 8", d.getNthParent(8));
-    }
-
     private static final String TEST1 = "public class Test {\n  void bar(String s) {\n   s = s.toLowerCase();\n  }\n}";
 
     @Ignore
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TypeDisambiguationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TypeDisambiguationTest.kt
index 3110b12be9..c400d74f2e 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TypeDisambiguationTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TypeDisambiguationTest.kt
@@ -4,6 +4,8 @@
 
 package net.sourceforge.pmd.lang.java.ast
 
+import io.kotest.matchers.collections.shouldBeEmpty
+import io.kotest.matchers.collections.shouldHaveSize
 import io.kotest.matchers.shouldBe
 import io.kotest.matchers.types.shouldBeSameInstanceAs
 import net.sourceforge.pmd.lang.ast.test.*
@@ -70,6 +72,30 @@ class TypeDisambiguationTest : ParserTestSpec({
         }
     }
 
+    parserTest("Package names in module") {
+
+        val code = """
+            module java.base {
+               opens java.util;
+               provides java.util.Map with java.util.HashMap;
+               //       ^^^^^^^^^          ^^^^^^^^^
+            }
+        """
+
+        doTest("test without disambig") {
+            val acu = parser.parse(code)
+
+            acu.descendants(ASTAmbiguousName::class.java).toList().shouldHaveSize(2)
+        }
+
+        doTest("test with disambig") {
+            enableProcessing()
+            val acu = parser.parse(code)
+
+            acu.descendants(ASTAmbiguousName::class.java).toList().shouldBeEmpty()
+        }
+    }
+
 
     parserTest("Failures") {
         val logger = enableProcessing()
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_anonymous_diamond.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_anonymous_diamond.java
similarity index 100%
rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_anonymous_diamond.java
rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_anonymous_diamond.java
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_invalid_identifier.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_invalid_identifier.java
similarity index 100%
rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_invalid_identifier.java
rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_invalid_identifier.java
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info.java
similarity index 80%
rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info.java
rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info.java
index 891a78fe51..efb9436604 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info.java
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info.java
@@ -12,4 +12,5 @@ open module com.example.foo {
     uses com.example.foo.spi.Intf;
 
     provides com.example.foo.spi.Intf with com.example.foo.Impl;
-}
\ No newline at end of file
+    provides com.example.foo.spi.Intf2 with com.example.foo.Impl, com.example.foo.Impl2;
+}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info.txt
new file mode 100644
index 0000000000..41fd39aff9
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info.txt
@@ -0,0 +1,20 @@
++- CompilationUnit[@PackageName = ""]
+   +- ModuleDeclaration[@Name = "com.example.foo", @Open = "true"]
+      +- ModuleName[@Name = "com.example.foo"]
+      +- ModuleRequiresDirective[@Static = "false", @Transitive = "false"]
+      |  +- ModuleName[@Name = "com.example.foo.http"]
+      +- ModuleRequiresDirective[@Static = "false", @Transitive = "false"]
+      |  +- ModuleName[@Name = "java.logging"]
+      +- ModuleRequiresDirective[@Static = "false", @Transitive = "true"]
+      |  +- ModuleName[@Name = "com.example.foo.network"]
+      +- ModuleExportsDirective[@PackageName = "com.example.foo.bar"]
+      +- ModuleExportsDirective[@PackageName = "com.example.foo.internal"]
+      |  +- ModuleName[@Name = "com.example.foo.probe"]
+      +- ModuleUsesDirective[@PackageName = "com.example.foo.spi.Intf"]
+      +- ModuleProvidesDirective[]
+      |  +- ClassOrInterfaceType[@FullyQualified = "true", @SimpleName = "Intf"]
+      |  +- ClassOrInterfaceType[@FullyQualified = "true", @SimpleName = "Impl"]
+      +- ModuleProvidesDirective[]
+         +- ClassOrInterfaceType[@FullyQualified = "true", @SimpleName = "Intf2"]
+         +- ClassOrInterfaceType[@FullyQualified = "true", @SimpleName = "Impl"]
+         +- ClassOrInterfaceType[@FullyQualified = "true", @SimpleName = "Impl2"]
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info_with_annot.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info_with_annot.java
similarity index 100%
rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info_with_annot.java
rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info_with_annot.java
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info_with_annot.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info_with_annot.txt
new file mode 100644
index 0000000000..122f27f1c3
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_module_info_with_annot.txt
@@ -0,0 +1,10 @@
++- CompilationUnit[@PackageName = ""]
+   +- ModuleDeclaration[@Name = "jdk.pack", @Open = "false"]
+      +- Annotation[@SimpleName = "Deprecated"]
+      |  +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Deprecated"]
+      |  +- AnnotationMemberList[@Empty = "false", @Size = "2"]
+      |     +- MemberValuePair[@Image = "since", @Name = "since", @Shorthand = "false"]
+      |     |  +- StringLiteral[@CompileTimeConstant = "true", @ConstValue = "11", @Empty = "false", @Image = "\"11\"", @Length = "2", @ParenthesisDepth = "0", @Parenthesized = "false", @TextBlock = "false"]
+      |     +- MemberValuePair[@Image = "forRemoval", @Name = "forRemoval", @Shorthand = "false"]
+      |        +- BooleanLiteral[@CompileTimeConstant = "true", @ParenthesisDepth = "0", @Parenthesized = "false", @True = "true"]
+      +- ModuleName[@Name = "jdk.pack"]
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_private_interface_methods.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_private_interface_methods.java
similarity index 100%
rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_private_interface_methods.java
rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_private_interface_methods.java
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_try_with_resources.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_try_with_resources.java
similarity index 81%
rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_try_with_resources.java
rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_try_with_resources.java
index fdc0d8fe60..7bc98d60f7 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_try_with_resources.java
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java9/jdk9_try_with_resources.java
@@ -1,3 +1,7 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
 public class InputJava9TryWithResources {
  public static void main() {
   MyResource resource1 = new MyResource();