Merge branch 'master' into 7.0.x
This commit is contained in:
@ -185,7 +185,7 @@ Example:
|
||||
* [apex](pmd_rules_apex.html) (Salesforce Apex)
|
||||
* [java](pmd_rules_java.html)
|
||||
* Supported Versions: 1.3, 1.4, 1.5, 5, 1.6, 6, 1.7, 7, 1.8, 8, 9, 1.9, 10, 1.10, 11, 12,
|
||||
13, 13-preview, 14 (default), 14-preview
|
||||
13, 14, 14-preview, 15 (default), 15-preview
|
||||
* [ecmascript](pmd_rules_ecmascript.html) (JavaScript)
|
||||
* [jsp](pmd_rules_jsp.html)
|
||||
* [modelica](pmd_rules_modelica.html)
|
||||
|
@ -19,6 +19,24 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
### New and noteworthy
|
||||
|
||||
#### Java 15 Support
|
||||
|
||||
This release of PMD brings support for Java 15. PMD can parse [Text Blocks](https://openjdk.java.net/jeps/378)
|
||||
which have been promoted to be a standard language feature of Java.
|
||||
|
||||
PMD also supports [Pattern Matching for instanceof](https://openjdk.java.net/jeps/375),
|
||||
[Records](https://openjdk.java.net/jeps/384), and [Sealed Classes](https://openjdk.java.net/jeps/360).
|
||||
|
||||
Note: The Pattern Matching for instanceof, Records, and Sealed Classes are all preview language features of OpenJDK 15
|
||||
and are not enabled by default. In order to
|
||||
analyze a project with PMD that uses these language features, you'll need to enable it via the environment
|
||||
variable `PMD_JAVA_OPTS` and select the new language version `15-preview`:
|
||||
|
||||
export PMD_JAVA_OPTS=--enable-preview
|
||||
./run.sh pmd -language java -version 15-preview ...
|
||||
|
||||
Note: Support for Java 13 preview language features have been removed. The version "13-preview" is no longer available.
|
||||
|
||||
#### Changes in how tab characters are handled
|
||||
|
||||
In the past, tab characters in source files has been handled differently in different languages by PMD.
|
||||
@ -65,6 +83,8 @@ See also [[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently #2656](
|
||||
* [#2653](https://github.com/pmd/pmd/issues/2653): \[lang-test] Upgrade kotlintest to Kotest
|
||||
* [#2656](https://github.com/pmd/pmd/pull/2656): \[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently
|
||||
* [#2690](https://github.com/pmd/pmd/pull/2690): \[core] Fix java7 compatibility
|
||||
* java
|
||||
* [#2646](https://github.com/pmd/pmd/issues/2646): \[java] Support JDK 15
|
||||
* java-bestpractices
|
||||
* [#2471](https://github.com/pmd/pmd/issues/2471): \[java] New Rule: AvoidReassigningCatchVariables
|
||||
* [#2663](https://github.com/pmd/pmd/issues/2663): \[java] NoClassDefFoundError on upgrade from 6.25.0 to 6.26.0
|
||||
|
@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Remove support for Java 13 preview language features.
|
||||
* Promote text blocks as a permanent language features with Java 15.
|
||||
* Support Pattern Matching for instanceof with Java 15 Preview.
|
||||
* Support Records with Java 15 Preview.
|
||||
* Support Local Records with Java 15 Preview.
|
||||
* Support Sealed Classes with Java 15 Preview.
|
||||
* Andreas Dangel 08/2020
|
||||
*====================================================================
|
||||
* Add support for record types introduced as a preview language
|
||||
* feature with Java 14. See JEP 359.
|
||||
* Andreas Dangel 02/2020
|
||||
@ -226,11 +234,13 @@ options {
|
||||
PARSER_BEGIN(JavaParserImpl)
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.sourceforge.pmd.lang.ast.CharStream;
|
||||
import net.sourceforge.pmd.lang.ast.GenericToken;
|
||||
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.TokenMgrError;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
|
||||
@ -282,9 +292,65 @@ class JavaParserImpl {
|
||||
/**
|
||||
* Semantic lookahead to check if the next identifier is a
|
||||
* specific restricted keyword.
|
||||
*
|
||||
* <p>Restricted keywords are:
|
||||
* var, yield, record, sealed, permits, "non" + "-" + "sealed"
|
||||
*
|
||||
* <p>enum and assert is used like restricted keywords, as they were not keywords
|
||||
* in the early java versions.
|
||||
*/
|
||||
private boolean isKeyword(String keyword) {
|
||||
return getToken(1).kind == IDENTIFIER && getToken(1).image.equals(keyword);
|
||||
private boolean isKeyword(String image) {
|
||||
return isKeyword(1, image);
|
||||
}
|
||||
|
||||
private boolean isKeyword(int index, String image) {
|
||||
Token token = getToken(index);
|
||||
return token.kind == IDENTIFIER && token.image.equals(image);
|
||||
}
|
||||
|
||||
private boolean isToken(int index, int kind) {
|
||||
return getToken(index).kind == kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Semantic lookahead which matches "non-sealed".
|
||||
*
|
||||
* <p>"non-sealed" cannot be a token, for several reasons:
|
||||
* It is only a keyword with java15 preview+, it consists actually
|
||||
* of several separate tokens, which are valid on their own.
|
||||
*/
|
||||
private boolean isNonSealedModifier() {
|
||||
if (isKeyword(1, "non") && isToken(2, MINUS) && isKeyword(3, "sealed")) {
|
||||
Token nonToken = getToken(1);
|
||||
Token minusToken = getToken(2);
|
||||
Token sealedToken = getToken(3);
|
||||
return nonToken.endColumn + 1 == minusToken.beginColumn
|
||||
&& minusToken.endColumn + 1 == sealedToken.beginColumn;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean classModifierLookahead() {
|
||||
Token next = getToken(1);
|
||||
return next.kind == AT
|
||||
|| next.kind == PUBLIC
|
||||
|| next.kind == PROTECTED
|
||||
|| next.kind == PRIVATE
|
||||
|| next.kind == ABSTRACT
|
||||
|| next.kind == STATIC
|
||||
|| next.kind == FINAL
|
||||
|| next.kind == STRICTFP
|
||||
|| isSealedClassSupported() && isKeyword("sealed")
|
||||
|| isSealedClassSupported() && isNonSealedModifier();
|
||||
}
|
||||
|
||||
private boolean localTypeDeclLookahead() {
|
||||
Token next = getToken(1);
|
||||
return next.kind == CLASS
|
||||
|| isRecordTypeSupported() && next.kind == INTERFACE
|
||||
|| isRecordTypeSupported() && next.kind == AT && isToken(2, INTERFACE)
|
||||
|| isRecordTypeSupported() && next.kind == IDENTIFIER && next.image.equals("enum")
|
||||
|| isRecordTypeSupported() && next.kind == IDENTIFIER && next.image.equals("record");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -828,6 +894,8 @@ int Modifiers() #void:
|
||||
| "volatile" { modifiers |= AccessNode.VOLATILE; }
|
||||
| "strictfp" { modifiers |= AccessNode.STRICTFP; }
|
||||
| "default" { modifiers |= AccessNode.DEFAULT; }
|
||||
| LOOKAHEAD({isKeyword("sealed")}) <IDENTIFIER> { modifiers |= AccessNode.SEALED; checkForSealedClassUsage(); }
|
||||
| LOOKAHEAD({isNonSealedModifier()}) <IDENTIFIER> <MINUS> <IDENTIFIER> { modifiers |= AccessNode.NON_SEALED; checkForSealedClassUsage(); }
|
||||
| Annotation()
|
||||
)
|
||||
)*
|
||||
@ -867,6 +935,7 @@ void ClassOrInterfaceDeclaration(int modifiers):
|
||||
[ TypeParameters() ]
|
||||
[ ExtendsList() ]
|
||||
[ ImplementsList() ]
|
||||
[ LOOKAHEAD({isKeyword("permits")}) PermittedSubclasses() ]
|
||||
ClassOrInterfaceBody()
|
||||
}
|
||||
|
||||
@ -886,6 +955,21 @@ void ImplementsList():
|
||||
( "," (TypeAnnotation())* ClassOrInterfaceType() )*
|
||||
}
|
||||
|
||||
void PermittedSubclasses() #PermitsList:
|
||||
{
|
||||
Token t;
|
||||
checkForSealedClassUsage();
|
||||
}
|
||||
{
|
||||
t = <IDENTIFIER> {
|
||||
if (!"permits".equals(t.image)) {
|
||||
throw new ParseException("ERROR: expecting permits");
|
||||
}
|
||||
}
|
||||
(TypeAnnotation())* ClassOrInterfaceType()
|
||||
( "," (TypeAnnotation())* ClassOrInterfaceType() )*
|
||||
}
|
||||
|
||||
void EnumDeclaration(int modifiers):
|
||||
{
|
||||
|
||||
@ -1623,36 +1707,64 @@ void Block() :
|
||||
}
|
||||
|
||||
void BlockStatement():
|
||||
{}
|
||||
{int mods = 0;}
|
||||
{
|
||||
LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement()
|
||||
| LOOKAHEAD( { isYieldStart() } ) YieldStatement()
|
||||
|
|
||||
LOOKAHEAD(( "final" | Annotation() )* Type() <IDENTIFIER>)
|
||||
LocalVariableDeclaration() ";"
|
||||
| LOOKAHEAD( "@" | "final" )
|
||||
// this eagerly parses all modifiers and annotations. After that, either a local type declaration
|
||||
// or a local variable declaration follows.
|
||||
// This allows more modifiers for local variables than actually allowed
|
||||
// and the annotations for local variables need to be moved in the AST down again.
|
||||
mods=Modifiers()
|
||||
(
|
||||
LOOKAHEAD({localTypeDeclLookahead()}) LocalTypeDecl(mods)
|
||||
|
|
||||
{
|
||||
List<Node> annotationsAndChildren = new ArrayList<Node>();
|
||||
while (jjtree.peekNode() instanceof ASTAnnotation) {
|
||||
annotationsAndChildren.add(jjtree.popNode());
|
||||
}
|
||||
}
|
||||
LocalVariableDeclaration()
|
||||
{
|
||||
ASTLocalVariableDeclaration localVarDecl = (ASTLocalVariableDeclaration) jjtree.peekNode();
|
||||
if ((mods & AccessNode.FINAL) == AccessNode.FINAL) {
|
||||
localVarDecl.setFinal(true);
|
||||
}
|
||||
if (!annotationsAndChildren.isEmpty()) {
|
||||
Collections.reverse(annotationsAndChildren);
|
||||
for (int i = 0; i < localVarDecl.getNumChildren(); i++) {
|
||||
annotationsAndChildren.add(localVarDecl.getChild(i));
|
||||
}
|
||||
for (int i = 0; i < annotationsAndChildren.size(); i++) {
|
||||
Node child = annotationsAndChildren.get(i);
|
||||
child.jjtSetParent(localVarDecl);
|
||||
localVarDecl.jjtAddChild(child, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
";"
|
||||
)
|
||||
| LOOKAHEAD({classModifierLookahead() || localTypeDeclLookahead()})
|
||||
mods=Modifiers()
|
||||
LocalTypeDecl(mods)
|
||||
| LOOKAHEAD(Type() <IDENTIFIER>)
|
||||
LocalVariableDeclaration() ";"
|
||||
|
|
||||
Statement()
|
||||
|
|
||||
// we don't need to lookahead further here
|
||||
// the ambiguity between start of local class and local variable decl
|
||||
// is already handled in the lookahead guarding LocalVariableDeclaration above.
|
||||
LocalClassDecl()
|
||||
}
|
||||
|
||||
void LocalClassDecl() #void:
|
||||
{int mods = 0;}
|
||||
void LocalTypeDecl(int mods) #void:
|
||||
{}
|
||||
{
|
||||
// this preserves the modifiers of the local class.
|
||||
// it allows for modifiers that are forbidden for local classes,
|
||||
// but anyway we are *not* checking modifiers for incompatibilities
|
||||
// anywhere else in this grammar (and indeed the production Modifiers
|
||||
// accepts any modifier explicitly for the purpose of forgiving modifier errors,
|
||||
// and reporting them later if needed --see its documentation).
|
||||
|
||||
// In particular, it unfortunately allows local class declarations to start
|
||||
// with a "default" modifier, which introduces an ambiguity with default
|
||||
// switch labels. This is guarded by a custom lookahead around SwitchLabel
|
||||
mods=Modifiers() ClassOrInterfaceDeclaration(mods)
|
||||
(
|
||||
LOOKAHEAD(<CLASS>) ClassOrInterfaceDeclaration(mods)
|
||||
| LOOKAHEAD(<INTERFACE>) ClassOrInterfaceDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
|
||||
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
|
||||
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
|
||||
| AnnotationTypeDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -28,9 +28,10 @@ public class JavaLanguageModule extends BaseLanguageModule {
|
||||
addVersion("11", new JavaLanguageHandler(11));
|
||||
addVersion("12", new JavaLanguageHandler(12));
|
||||
addVersion("13", new JavaLanguageHandler(13));
|
||||
addVersion("13-preview", new JavaLanguageHandler(13, true));
|
||||
addDefaultVersion("14", new JavaLanguageHandler(14)); // 14 is the default
|
||||
addVersion("14", new JavaLanguageHandler(14));
|
||||
addVersion("14-preview", new JavaLanguageHandler(14, true));
|
||||
addDefaultVersion("15", new JavaLanguageHandler(15)); // 15 is the default
|
||||
addVersion("15-preview", new JavaLanguageHandler(15, true));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ public class ASTAnnotationTypeDeclaration extends AbstractAnyTypeDeclaration {
|
||||
return TypeKind.ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocal() {
|
||||
return getParent() instanceof ASTBlockStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeStream<ASTAnyTypeBodyDeclaration> getDeclarations() {
|
||||
|
@ -107,6 +107,10 @@ public interface ASTAnyTypeDeclaration extends TypeNode, JavaQualifiableNode, Ac
|
||||
return getFirstChildOfType(ASTRecordComponentList.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this type is declared locally, e.g. in the context of a method block.
|
||||
*/
|
||||
boolean isLocal();
|
||||
|
||||
/**
|
||||
* The kind of type this node declares.
|
||||
|
@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.internal.util.IteratorUtil;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
@ -100,4 +101,23 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration {
|
||||
return it == null ? Collections.emptyList() : IteratorUtil.toList(it.iterator());
|
||||
}
|
||||
|
||||
@Experimental
|
||||
public List<ASTClassOrInterfaceType> getPermittedSubclasses() {
|
||||
ASTPermitsList permitted = getFirstChildOfType(ASTPermitsList.class);
|
||||
return permitted == null
|
||||
? Collections.<ASTClassOrInterfaceType>emptyList()
|
||||
: CollectionUtil.toList(permitted.iterator());
|
||||
}
|
||||
|
||||
@Experimental
|
||||
public boolean isSealed() {
|
||||
int modifiers = getModifiers();
|
||||
return (modifiers & AccessNode.SEALED) == AccessNode.SEALED;
|
||||
}
|
||||
|
||||
@Experimental
|
||||
public boolean isNonSealed() {
|
||||
int modifiers = getModifiers();
|
||||
return (modifiers & AccessNode.NON_SEALED) == AccessNode.NON_SEALED;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ public class ASTEnumDeclaration extends AbstractAnyTypeDeclaration {
|
||||
return TypeKind.ENUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocal() {
|
||||
return getParent() instanceof ASTBlockStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeStream<ASTAnyTypeBodyDeclaration> getDeclarations() {
|
||||
|
@ -12,7 +12,6 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
|
||||
public class ASTLiteral extends AbstractJavaTypeNode {
|
||||
@ -261,10 +260,7 @@ public class ASTLiteral extends AbstractJavaTypeNode {
|
||||
* Returns the content of the text block after normalizing line endings to LF,
|
||||
* removing incidental white space surrounding the text block and interpreting
|
||||
* escape sequences.
|
||||
*
|
||||
* <p>Note: This is a Java 14 Preview Feature.
|
||||
*/
|
||||
@Experimental
|
||||
public String getTextBlockContent() {
|
||||
if (!isTextBlock()) {
|
||||
return getImage();
|
||||
|
@ -8,7 +8,7 @@ import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
/**
|
||||
* A pattern (for pattern matching constructs like {@link ASTInstanceOfExpression InstanceOfExpression}).
|
||||
* This is a JDK 14 preview feature and is subject to change.
|
||||
* This is a JDK 14 and JDK 15 preview feature and is subject to change.
|
||||
*
|
||||
* <p>This interface will be implemented by all forms of patterns. For
|
||||
* now, only type test patterns are supported. Record deconstruction
|
||||
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the {@code permits} clause of a (sealed) class declaration.
|
||||
*
|
||||
* <p>This is a Java 15 Preview feature.
|
||||
*
|
||||
* <p>See https://openjdk.java.net/jeps/360
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* PermittedSubclasses ::= "permits" (TypeAnnotation)* ClassOrInterfaceType
|
||||
* ( "," (TypeAnnotation)* ClassOrInterfaceType )*
|
||||
* </pre>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTPermitsList extends AbstractJavaNode implements Iterable<ASTClassOrInterfaceType> {
|
||||
|
||||
ASTPermitsList(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
ASTPermitsList(JavaParser p, int id) {
|
||||
super(p, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<ASTClassOrInterfaceType> iterator() {
|
||||
return new NodeChildrenIterator<>(this, ASTClassOrInterfaceType.class);
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
/**
|
||||
* Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature).
|
||||
* Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
|
||||
* This can contain additional methods and or constructors.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
|
@ -8,7 +8,7 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
/**
|
||||
* Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature).
|
||||
* Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
|
@ -10,7 +10,7 @@ import java.util.Iterator;
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
/**
|
||||
* Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature).
|
||||
* Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
|
@ -8,7 +8,7 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
/**
|
||||
* This defines a compact constructor for a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature).
|
||||
* This defines a compact constructor for a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
|
@ -12,7 +12,7 @@ import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.NodeStream;
|
||||
|
||||
/**
|
||||
* A record declaration is a special data class type (JDK 14 preview feature).
|
||||
* A record declaration is a special data class type (JDK 14 and JDK 15 preview feature).
|
||||
* This is a {@linkplain Node#isFindBoundary() find boundary} for tree traversal methods.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
@ -26,7 +26,7 @@ import net.sourceforge.pmd.lang.ast.NodeStream;
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://openjdk.java.net/jeps/359">JEP 359: Records (Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/384">JEP 384: Records (Second Preview)</a>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration {
|
||||
@ -54,9 +54,20 @@ public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration {
|
||||
return isNested();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ASTRecordComponentList getRecordComponents() {
|
||||
public boolean isFinal() {
|
||||
// A record is implicitly final
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocal() {
|
||||
return getParent() instanceof ASTBlockStatement;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NonNull ASTRecordComponentList getRecordComponents() {
|
||||
return getFirstChildOfType(ASTRecordComponentList.class);
|
||||
}
|
||||
}
|
||||
|
@ -197,6 +197,11 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getParent() instanceof ASTRecordComponent) {
|
||||
// the field corresponding to this record component is declared final
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getParent() instanceof ASTFormalParameter) {
|
||||
// This accounts for exception parameters too for now
|
||||
return ((ASTFormalParameter) getParent()).isFinal();
|
||||
|
@ -23,6 +23,8 @@ public interface AccessNode extends JavaNode {
|
||||
int VOLATILE = 0x0200;
|
||||
int STRICTFP = 0x1000;
|
||||
int DEFAULT = 0x2000;
|
||||
int SEALED = 0x4000;
|
||||
int NON_SEALED = 0x8000;
|
||||
|
||||
|
||||
int getModifiers();
|
||||
|
@ -40,7 +40,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
public List<String> innerClasses;
|
||||
|
||||
public PMDASMVisitor(String outerName) {
|
||||
super(Opcodes.ASM7);
|
||||
super(Opcodes.ASM9);
|
||||
this.outerName = outerName;
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDFieldVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM5);
|
||||
super(Opcodes.ASM9);
|
||||
parent = visitor;
|
||||
}
|
||||
|
||||
@ -196,7 +196,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDAnnotationVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM5);
|
||||
super(Opcodes.ASM9);
|
||||
parent = visitor;
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDSignatureVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM5);
|
||||
super(Opcodes.ASM9);
|
||||
this.parent = visitor;
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDMethodVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM5);
|
||||
super(Opcodes.ASM9);
|
||||
parent = visitor;
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,8 @@ public class LanguageVersionDiscovererTest {
|
||||
File javaFile = new File("/path/to/MyClass.java");
|
||||
|
||||
LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile);
|
||||
assertEquals("LanguageVersion must be Java 14 !",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14"), languageVersion);
|
||||
assertEquals("LanguageVersion must be Java 15 !",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), languageVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,7 +48,7 @@ public class LanguageVersionDiscovererTest {
|
||||
public void testLanguageVersionDiscoverer() {
|
||||
PMDConfiguration configuration = new PMDConfiguration();
|
||||
LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer();
|
||||
assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14"),
|
||||
assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"),
|
||||
languageVersionDiscoverer
|
||||
.getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME)));
|
||||
configuration
|
||||
|
@ -52,6 +52,10 @@ public class LanguageVersionTest extends AbstractLanguageVersionTest {
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14"), },
|
||||
{ JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "14-preview",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14-preview"), },
|
||||
{ JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "15",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), },
|
||||
{ JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "15-preview",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15-preview"), },
|
||||
|
||||
// this one won't be found: case sensitive!
|
||||
{ "JAVA", "JAVA", "1.7", null, },
|
||||
|
@ -1,91 +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.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
|
||||
|
||||
public class Java13Test {
|
||||
|
||||
|
||||
private final JavaParsingHelper java12 =
|
||||
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("12")
|
||||
.withResourceContext(Java13Test.class, "jdkversiontests/java13/");
|
||||
|
||||
private final JavaParsingHelper java13p = java12.withDefaultVersion("13-preview");
|
||||
|
||||
|
||||
@Test
|
||||
public void testSwitchExpressions() {
|
||||
ASTCompilationUnit compilationUnit = java13p.parseResource("SwitchExpressions.java");
|
||||
|
||||
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(4, switchExpression.getNumChildren());
|
||||
Assert.assertTrue(switchExpression.getChild(0) instanceof ASTExpression);
|
||||
Assert.assertEquals(3, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size());
|
||||
Assert.assertEquals(1, switchExpression.findChildrenOfType(ASTSwitchLabeledBlock.class).size());
|
||||
Assert.assertEquals(1, switchExpression.findDescendantsOfType(ASTYieldStatement.class).size());
|
||||
ASTYieldStatement yieldStatement = switchExpression.getFirstDescendantOfType(ASTYieldStatement.class);
|
||||
Assert.assertEquals(Integer.TYPE, yieldStatement.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchExpressionsYield() {
|
||||
ASTCompilationUnit compilationUnit = java13p.parseResource("SwitchExpressionsYield.java");
|
||||
|
||||
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(11, switchExpression.getNumChildren());
|
||||
Assert.assertTrue(switchExpression.getChild(0) instanceof ASTExpression);
|
||||
Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabel.class).size());
|
||||
|
||||
ASTYieldStatement yieldStatement = switchExpression.getFirstDescendantOfType(ASTYieldStatement.class);
|
||||
Assert.assertEquals("SwitchExpressionsBreak.SIX", yieldStatement.getImage());
|
||||
Assert.assertTrue(yieldStatement.getChild(0) instanceof ASTExpression);
|
||||
|
||||
ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class)
|
||||
.get(1);
|
||||
ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class);
|
||||
Assert.assertEquals(Integer.TYPE, localVarDecl.getType());
|
||||
Assert.assertEquals(Integer.TYPE, switchExpression.getType());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void testSwitchExpressionsBeforeJava13() {
|
||||
java12.parseResource("SwitchExpressions.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextBlocks() {
|
||||
ASTCompilationUnit compilationUnit = java13p.parseResource("TextBlocks.java");
|
||||
List<ASTLiteral> literals = compilationUnit.findDescendantsOfType(ASTLiteral.class);
|
||||
Assert.assertEquals(10, literals.size());
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ASTLiteral literal = literals.get(i);
|
||||
Assert.assertTrue(literal.isTextBlock());
|
||||
}
|
||||
Assert.assertEquals("\"\"\"\n"
|
||||
+ " <html>\n"
|
||||
+ " <body>\n"
|
||||
+ " <p>Hello, world</p>\n"
|
||||
+ " </body>\n"
|
||||
+ " </html>\n"
|
||||
+ " \"\"\"",
|
||||
literals.get(0).getImage());
|
||||
Assert.assertFalse(literals.get(8).isTextBlock());
|
||||
Assert.assertTrue(literals.get(9).isTextBlock());
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void testTextBlocksBeforeJava13() {
|
||||
java12.parseResource("TextBlocks.java");
|
||||
}
|
||||
|
||||
}
|
@ -27,15 +27,12 @@ public class Java14Test {
|
||||
|
||||
private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview");
|
||||
private final JavaParsingHelper java13 = java14.withDefaultVersion("13");
|
||||
private final JavaParsingHelper java13p = java14.withDefaultVersion("13-preview");
|
||||
|
||||
/**
|
||||
* Tests switch expressions with yield.
|
||||
* The switch expressions have no changed between java 13-preview and 14, so behave exactly the same.
|
||||
*/
|
||||
@Test
|
||||
public void switchExpressions() {
|
||||
parseAndCheckSwitchExpression(java13p);
|
||||
parseAndCheckSwitchExpression(java14);
|
||||
parseAndCheckSwitchExpression(java14p);
|
||||
}
|
||||
@ -85,11 +82,6 @@ public class Java14Test {
|
||||
|
||||
@Test
|
||||
public void checkYieldConditionalBehaviour() {
|
||||
checkYieldStatements(java13p);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkYieldConditionalBehaviourJ14() {
|
||||
checkYieldStatements(java14);
|
||||
}
|
||||
|
||||
@ -140,7 +132,6 @@ public class Java14Test {
|
||||
|
||||
@Test
|
||||
public void multipleCaseLabels() {
|
||||
multipleCaseLabels(java13p);
|
||||
multipleCaseLabels(java14);
|
||||
multipleCaseLabels(java14p);
|
||||
}
|
||||
@ -156,7 +147,6 @@ public class Java14Test {
|
||||
|
||||
@Test
|
||||
public void switchRules() {
|
||||
switchRules(java13p);
|
||||
switchRules(java14);
|
||||
switchRules(java14p);
|
||||
}
|
||||
@ -184,7 +174,6 @@ public class Java14Test {
|
||||
|
||||
@Test
|
||||
public void simpleSwitchExpressions() {
|
||||
simpleSwitchExpressions(java13p);
|
||||
simpleSwitchExpressions(java14);
|
||||
simpleSwitchExpressions(java14p);
|
||||
}
|
||||
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest;
|
||||
import net.sourceforge.pmd.lang.ast.test.RelevantAttributePrinter;
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
|
||||
|
||||
public class Java15PreviewTreeDumpTest extends BaseTreeDumpTest {
|
||||
private final JavaParsingHelper java15p =
|
||||
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("15-preview")
|
||||
.withResourceContext(Java15PreviewTreeDumpTest.class, "jdkversiontests/java15p/");
|
||||
private final JavaParsingHelper java15 = java15p.withDefaultVersion("15");
|
||||
|
||||
public Java15PreviewTreeDumpTest() {
|
||||
super(new RelevantAttributePrinter(), ".java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseParsingHelper<?, ?> getParser() {
|
||||
return java15p;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patternMatchingInstanceof() {
|
||||
doTest("PatternMatchingInstanceof");
|
||||
|
||||
// extended tests for type resolution etc.
|
||||
ASTCompilationUnit compilationUnit = java15p.parseResource("PatternMatchingInstanceof.java");
|
||||
List<ASTInstanceOfExpression> instanceOfExpressions = compilationUnit.findDescendantsOfType(ASTInstanceOfExpression.class);
|
||||
for (ASTInstanceOfExpression expr : instanceOfExpressions) {
|
||||
ASTVariableDeclaratorId variable = expr.getChild(1).getFirstChildOfType(ASTVariableDeclaratorId.class);
|
||||
Assert.assertEquals(String.class, variable.getType());
|
||||
// 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 patternMatchingInstanceofBeforeJava15PreviewShouldFail() {
|
||||
java15.parseResource("PatternMatchingInstanceof.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recordPoint() {
|
||||
doTest("Point");
|
||||
|
||||
// extended tests for type resolution etc.
|
||||
ASTCompilationUnit compilationUnit = java15p.parseResource("Point.java");
|
||||
ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class);
|
||||
List<ASTRecordComponent> components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class)
|
||||
.findChildrenOfType(ASTRecordComponent.class);
|
||||
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 recordPointBeforeJava15PreviewShouldFail() {
|
||||
java15.parseResource("Point.java");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordCtorWithThrowsShouldFail() {
|
||||
java15p.parse(" record R {"
|
||||
+ " R throws IOException {}"
|
||||
+ " }");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordMustNotExtend() {
|
||||
java15p.parse("record RecordEx(int x) extends Number { }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void innerRecords() {
|
||||
doTest("Records");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordIsARestrictedIdentifier() {
|
||||
java15p.parse("public class record {}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localRecords() {
|
||||
doTest("LocalRecords");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void sealedClassBeforeJava15Preview() {
|
||||
java15.parseResource("geometry/Shape.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sealedClass() {
|
||||
doTest("geometry/Shape");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonSealedClass() {
|
||||
doTest("geometry/Square");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void sealedInterfaceBeforeJava15Preview() {
|
||||
java15.parseResource("expression/Expr.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sealedInterface() {
|
||||
doTest("expression/Expr");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localInterfaceAndEnums() {
|
||||
doTest("LocalInterfacesAndEnums");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void localInterfacesAndEnumsBeforeJava15PreviewShouldFail() {
|
||||
java15.parseResource("LocalInterfacesAndEnums.java");
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest;
|
||||
import net.sourceforge.pmd.lang.ast.test.RelevantAttributePrinter;
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
|
||||
|
||||
public class Java15TreeDumpTest extends BaseTreeDumpTest {
|
||||
private final JavaParsingHelper java15 =
|
||||
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("15")
|
||||
.withResourceContext(Java15TreeDumpTest.class, "jdkversiontests/java15/");
|
||||
private final JavaParsingHelper java15p = java15.withDefaultVersion("15-preview");
|
||||
private final JavaParsingHelper java14 = java15.withDefaultVersion("14");
|
||||
|
||||
public Java15TreeDumpTest() {
|
||||
super(new RelevantAttributePrinter(), ".java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseParsingHelper<?, ?> getParser() {
|
||||
return java15;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void textBlocks() {
|
||||
doTest("TextBlocks");
|
||||
java15p.parseResource("TextBlocks.java"); // make sure we can parse it with preview as well
|
||||
}
|
||||
|
||||
@Test(expected = net.sourceforge.pmd.lang.ast.ParseException.class)
|
||||
public void textBlocksBeforeJava15ShouldFail() {
|
||||
java14.parseResource("TextBlocks.java");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void stringEscapeSequenceShouldFail() {
|
||||
java14.parse("class Foo { String s =\"a\\sb\"; }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sealedAndNonSealedIdentifiers() {
|
||||
doTest("NonSealedIdentifier");
|
||||
java15p.parseResource("NonSealedIdentifier.java"); // make sure we can parse it with preview as well
|
||||
}
|
||||
}
|
@ -6,22 +6,24 @@ package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import net.sourceforge.pmd.lang.ast.test.shouldBe
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.J14__PREVIEW
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.J15__PREVIEW
|
||||
import java.io.IOException
|
||||
|
||||
class ASTPatternTest : ParserTestSpec({
|
||||
|
||||
parserTest("Test patterns only available on JDK 14 (preview)", javaVersions = !J14__PREVIEW) {
|
||||
parserTest("Test patterns only available on JDK 14+15 (preview)", javaVersions = JavaVersion.values().asList().minus(J14__PREVIEW).minus(J15__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")
|
||||
it.message.shouldContain("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
parserTest("Test simple patterns", javaVersion = J14__PREVIEW) {
|
||||
parserTest("Test simple patterns", javaVersions = listOf(J14__PREVIEW, J15__PREVIEW)) {
|
||||
|
||||
importedTypes += IOException::class.java
|
||||
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import io.kotest.matchers.shouldBe
|
||||
import net.sourceforge.pmd.lang.ast.test.matchNode
|
||||
|
||||
class Java15KotlinTest: ParserTestSpec( {
|
||||
|
||||
// Note: More tests are in ASTLiteralTest.
|
||||
parserTest("textBlocks", javaVersions = JavaVersion.J15..JavaVersion.Latest) {
|
||||
("\"\"\"\n" +
|
||||
" <html> \n" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p> \n" +
|
||||
" </body> \n" +
|
||||
" </html> \n" +
|
||||
" \"\"\"") should matchExpr<ASTExpression> {
|
||||
child<ASTPrimaryExpression> {
|
||||
child<ASTPrimaryPrefix> {
|
||||
child<ASTLiteral> {
|
||||
it.isTextBlock shouldBe true
|
||||
it.escapedStringLiteral shouldBe
|
||||
"\"\"\"\n" +
|
||||
" <html> \n" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p> \n" +
|
||||
" </body> \n" +
|
||||
" </html> \n" +
|
||||
" \"\"\""
|
||||
it.textBlockContent shouldBe
|
||||
"<html>\n" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p>\n" +
|
||||
" </body>\n" +
|
||||
"</html>\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
@ -23,8 +23,9 @@ import java.beans.PropertyDescriptor
|
||||
enum class JavaVersion : Comparable<JavaVersion> {
|
||||
J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11,
|
||||
J12,
|
||||
J13, J13__PREVIEW,
|
||||
J14, J14__PREVIEW;
|
||||
J13,
|
||||
J14, J14__PREVIEW,
|
||||
J15, J15__PREVIEW;
|
||||
|
||||
/** Name suitable for use with e.g. [JavaParsingHelper.parse] */
|
||||
val pmdName: String = name.removePrefix("J").replaceFirst("__", "-").replace('_', '.').toLowerCase()
|
||||
|
@ -1,41 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see <a href="http://openjdk.java.net/jeps/354">JEP 354: Switch Expressions (Preview)</a>
|
||||
*/
|
||||
public class SwitchExpressions {
|
||||
private enum Day {
|
||||
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Day day = Day.FRIDAY;
|
||||
|
||||
int j = switch (day) {
|
||||
case MONDAY -> 0;
|
||||
case TUESDAY -> 1;
|
||||
default -> {
|
||||
int k = day.toString().length();
|
||||
int result = f(k);
|
||||
yield result;
|
||||
}
|
||||
};
|
||||
System.out.printf("j = %d%n", j);
|
||||
|
||||
String s = "Bar";
|
||||
int result = switch (s) {
|
||||
case "Foo":
|
||||
yield 1;
|
||||
case "Bar":
|
||||
yield 2;
|
||||
default:
|
||||
System.out.println("Neither Foo nor Bar, hmmm...");
|
||||
yield 0;
|
||||
};
|
||||
System.out.printf("result = %d%n", result);
|
||||
}
|
||||
|
||||
private static int f(int k) {
|
||||
return k+1;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @see <a href="https://openjdk.java.net/jeps/325">JEP 325: Switch Expressions (Preview)</a>
|
||||
*/
|
||||
public class SwitchExpressionsYield {
|
||||
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: yield SwitchExpressionsBreak.SIX;
|
||||
case TUESDAY : yield 7;
|
||||
case THURSDAY, SATURDAY : yield 8;
|
||||
case WEDNESDAY : yield 9;
|
||||
default : {
|
||||
int k = day * 2;
|
||||
int result = f(k);
|
||||
yield result;
|
||||
}
|
||||
};
|
||||
System.out.printf("NumLetters: %d%n", numLetters);
|
||||
}
|
||||
|
||||
private static int f(int k) {
|
||||
return k*3;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user