Merge branch 'java-16-support' into pmd7-java-16-support
This commit is contained in:
@ -19,10 +19,40 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
### New and noteworthy
|
||||
|
||||
#### Java 16 Support
|
||||
|
||||
This release of PMD brings support for Java 16. PMD supports [JEP 394: Pattern Matching for instanceof](https://openjdk.java.net/jeps/394) and [JEP 395: Records](https://openjdk.java.net/jeps/395). Both have been promoted
|
||||
to be a standard language feature of Java 16.
|
||||
|
||||
PMD also supports [JEP 397: Sealed Classes (Second Preview)](https://openjdk.java.net/jeps/397) as a preview
|
||||
language feature. 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 `16-preview`:
|
||||
|
||||
export PMD_JAVA_OPTS=--enable-preview
|
||||
./run.sh pmd -language java -version 16-preview ...
|
||||
|
||||
Note: Support for Java 14 preview language features have been removed. The version "14-preview" is no longer available.
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
### API Changes
|
||||
|
||||
#### pmd-java
|
||||
|
||||
* The experimental class `ASTTypeTestPattern` has been renamed to {% jdoc java::lang.java.ast.ASTTypePattern %}
|
||||
in order to align the naming to the JLS.
|
||||
* The experimental class `ASTRecordConstructorDeclaration` has been renamed to {% jdoc java::lang.java.ast.ASTCompactConstructorDeclaration %}
|
||||
in order to align the naming to the JLS.
|
||||
* The AST types and APIs around Pattern Matching and Records are not experimental anymore:
|
||||
* {% jdoc !!java::lang.java.ast.ASTVariableDeclaratorId#isPatternBinding() %}
|
||||
* {% jdoc java::lang.java.ast.ASTPattern %}
|
||||
* {% jdoc java::lang.java.ast.ASTTypePattern %}
|
||||
* {% jdoc java::lang.java.ast.ASTRecordDeclaration %}
|
||||
* {% jdoc java::lang.java.ast.ASTRecordComponentList %}
|
||||
* {% jdoc java::lang.java.ast.ASTRecordComponent %}
|
||||
* {% jdoc java::lang.java.ast.ASTRecordBody %}
|
||||
* {% jdoc java::lang.java.ast.ASTCompactConstructorDeclaration %}
|
||||
|
||||
### External Contributions
|
||||
|
||||
{% endtocmaker %}
|
||||
|
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* Remove support for Java 14 preview language features
|
||||
* JEP 397: Sealed Classes (Second Preview) for Java16 Preview
|
||||
* JEP 395: Records for Java16
|
||||
* JEP 394: Pattern Matching for instanceof for Java16
|
||||
* Andreas Dangel 02/2021
|
||||
*====================================================================
|
||||
* 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.
|
||||
@ -273,7 +279,7 @@ class JavaParserImpl {
|
||||
|
||||
|
||||
private boolean isRecordTypeSupported() {
|
||||
return (jdkVersion == 14 || jdkVersion == 15) && preview;
|
||||
return jdkVersion == 15 && preview || jdkVersion >= 16;
|
||||
}
|
||||
|
||||
private boolean localTypesSupported() {
|
||||
@ -281,10 +287,9 @@ class JavaParserImpl {
|
||||
}
|
||||
|
||||
private boolean isSealedClassSupported() {
|
||||
return jdkVersion == 15 && preview;
|
||||
return jdkVersion == 15 && preview || jdkVersion == 16 && preview;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Keeps track during tree construction, whether we are currently building a switch label.
|
||||
* A switch label must not contain a LambdaExpression.
|
||||
@ -295,7 +300,6 @@ class JavaParserImpl {
|
||||
*/
|
||||
private boolean inSwitchLabel = false;
|
||||
|
||||
|
||||
// This is a semantic LOOKAHEAD to determine if we're dealing with an assert
|
||||
// Note that this can't be replaced with a syntactic lookahead
|
||||
// since "assert" isn't a string literal token
|
||||
@ -1037,8 +1041,8 @@ void PermittedSubclasses() #PermitsList:
|
||||
throw new ParseException("ERROR: expecting permits");
|
||||
}
|
||||
}
|
||||
(TypeAnnotation())* ClassOrInterfaceType()
|
||||
( "," (TypeAnnotation())* ClassOrInterfaceType() )*
|
||||
TypeName()
|
||||
( "," TypeName() )*
|
||||
}
|
||||
|
||||
void EnumDeclaration():
|
||||
@ -1084,15 +1088,21 @@ void RecordDeclaration():
|
||||
}
|
||||
t=<IDENTIFIER> {jjtThis.setImage(t.image);}
|
||||
[ TypeParameters() ]
|
||||
RecordComponentList()
|
||||
RecordHeader()
|
||||
[ ImplementsList() ]
|
||||
RecordBody()
|
||||
}
|
||||
|
||||
void RecordHeader() #void:
|
||||
{}
|
||||
{
|
||||
"(" RecordComponentList() ")"
|
||||
}
|
||||
|
||||
void RecordComponentList() :
|
||||
{}
|
||||
{
|
||||
"(" [ RecordComponent() ("," RecordComponent())* ] ")"
|
||||
[ RecordComponent() ("," RecordComponent())* ]
|
||||
}
|
||||
|
||||
void RecordComponent():
|
||||
@ -1100,7 +1110,7 @@ void RecordComponent():
|
||||
{
|
||||
ModAnnotationList()
|
||||
FormalParamType()
|
||||
VariableIdWithDims()
|
||||
VariableDeclaratorId()
|
||||
}
|
||||
|
||||
void RecordBody():
|
||||
@ -1114,18 +1124,18 @@ void RecordBody():
|
||||
void RecordBodyDeclaration() #void :
|
||||
{}
|
||||
{
|
||||
LOOKAHEAD(RecordCtorLookahead()) ModifierList() RecordConstructorDeclaration()
|
||||
LOOKAHEAD(CompactConstructorDeclarationLookahead()) ModifierList() CompactConstructorDeclaration()
|
||||
|
|
||||
ClassOrInterfaceBodyDeclaration()
|
||||
}
|
||||
|
||||
private void RecordCtorLookahead() #void:
|
||||
private void CompactConstructorDeclarationLookahead() #void:
|
||||
{}
|
||||
{
|
||||
ModifierList() <IDENTIFIER> "{"
|
||||
}
|
||||
|
||||
void RecordConstructorDeclaration():
|
||||
void CompactConstructorDeclaration():
|
||||
{}
|
||||
{
|
||||
<IDENTIFIER> { jjtThis.setImage(token.image); }
|
||||
@ -1313,6 +1323,17 @@ void Initializer() :
|
||||
[ "static" {jjtThis.setStatic();} ] Block()
|
||||
}
|
||||
|
||||
void TypeName() #ClassOrInterfaceType:
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
Token t;
|
||||
}
|
||||
{
|
||||
t=<IDENTIFIER> {s.append(t.image);}
|
||||
( "." t=<IDENTIFIER> {s.append('.').append(t.image);} )*
|
||||
{jjtThis.setImage(s.toString());}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1669,7 +1690,11 @@ void InstanceOfExpression() #void:
|
||||
RelationalExpression() [
|
||||
LOOKAHEAD(1)
|
||||
("instanceof"
|
||||
AnnotatedRefType() [ BindingVarId() #TypeTestPattern(2) ]
|
||||
(
|
||||
AnnotatedRefType() [ BindingVarId() #TypePattern(2) ]
|
||||
|
|
||||
( LocalVarModifierList() ReferenceType() BindingVarId() ) #TypePattern(3)
|
||||
)
|
||||
{
|
||||
jjtThis.setOp(BinaryOp.INSTANCEOF);
|
||||
AbstractJavaNode top = jjtree.popNode();
|
||||
|
@ -29,9 +29,10 @@ public class JavaLanguageModule extends BaseLanguageModule {
|
||||
addVersion("12", new JavaLanguageHandler(12));
|
||||
addVersion("13", new JavaLanguageHandler(13));
|
||||
addVersion("14", new JavaLanguageHandler(14));
|
||||
addVersion("14-preview", new JavaLanguageHandler(14, true));
|
||||
addDefaultVersion("15", new JavaLanguageHandler(15)); // 15 is the default
|
||||
addVersion("15", new JavaLanguageHandler(15));
|
||||
addVersion("15-preview", new JavaLanguageHandler(15, true));
|
||||
addDefaultVersion("16", new JavaLanguageHandler(16)); // 16 is the default
|
||||
addVersion("16-preview", new JavaLanguageHandler(16, true));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,13 +5,11 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
|
||||
|
||||
/**
|
||||
* This defines a compact constructor for a {@link ASTRecordDeclaration RecordDeclaration}
|
||||
* (JDK 14 and JDK 15 preview feature). Compact constructors implicitly declares formal
|
||||
* parameters corresponding to the record component list. These can be
|
||||
* This defines a compact constructor for a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature).
|
||||
* Compact constructors implicitly declares formal parameters corresponding to the record component list. These can be
|
||||
* fetched from {@link #getSymbol()}.
|
||||
*
|
||||
* <p>Compact record constructors must be declared "public".
|
||||
@ -20,16 +18,15 @@ import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* RecordConstructorDeclaration ::= {@link ASTModifierList Modifiers}
|
||||
* CompactConstructorDeclaration ::= {@link ASTModifierList Modifiers}
|
||||
* <IDENTIFIER>
|
||||
* {@link ASTBlock Block}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTRecordConstructorDeclaration extends AbstractJavaNode implements ASTBodyDeclaration, SymbolDeclaratorNode, AccessNode {
|
||||
public final class ASTCompactConstructorDeclaration extends AbstractJavaNode implements ASTBodyDeclaration, SymbolDeclaratorNode, AccessNode {
|
||||
|
||||
ASTRecordConstructorDeclaration(int id) {
|
||||
ASTCompactConstructorDeclaration(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@ -42,7 +39,7 @@ public final class ASTRecordConstructorDeclaration extends AbstractJavaNode impl
|
||||
return getFirstChildOfType(ASTBlock.class);
|
||||
}
|
||||
|
||||
public ASTRecordConstructorDeclaration getDeclarationNode() {
|
||||
public ASTCompactConstructorDeclaration getDeclarationNode() {
|
||||
return this;
|
||||
}
|
||||
|
@ -1,29 +1,25 @@
|
||||
/**
|
||||
/*
|
||||
* 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.Experimental;
|
||||
|
||||
/**
|
||||
* A pattern (for pattern matching constructs like {@link ASTInstanceOfExpression InstanceOfExpression}).
|
||||
* This is a JDK 14 and JDK 15 preview feature and is subject to change.
|
||||
* This is a JDK 16 feature.
|
||||
*
|
||||
* <p>This interface will be implemented by all forms of patterns. For
|
||||
* now, only type test patterns are supported. Record deconstruction
|
||||
* patterns are in the works for JDK 15 preview.
|
||||
*
|
||||
* <p>See https://openjdk.java.net/jeps/305, https://openjdk.java.net/jeps/8235186
|
||||
* patterns is planned for a future JDK version.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* Pattern ::= {@link ASTTypeTestPattern TypeTestPattern}
|
||||
* Pattern ::= {@link ASTTypePattern TypePattern}
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://openjdk.java.net/jeps/394">JEP 394: Pattern Matching for instanceof</a>
|
||||
*/
|
||||
@Experimental
|
||||
public interface ASTPattern extends JavaNode {
|
||||
|
||||
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ import net.sourceforge.pmd.lang.java.ast.ASTList.ASTNonEmptyList;
|
||||
/**
|
||||
* Represents the {@code permits} clause of a (sealed) class declaration.
|
||||
*
|
||||
* <p>This is a Java 15 Preview feature.
|
||||
* <p>This is a Java 15 Preview and Java 16 Preview feature.
|
||||
*
|
||||
* <p>See https://openjdk.java.net/jeps/360
|
||||
* <p>See https://openjdk.java.net/jeps/397
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* PermittedSubclasses ::= "permits" (TypeAnnotation)* ClassOrInterfaceType
|
||||
* ( "," (TypeAnnotation)* ClassOrInterfaceType )*
|
||||
* PermittedSubclasses ::= "permits" ClassOrInterfaceType
|
||||
* ( "," ClassOrInterfaceType )*
|
||||
* </pre>
|
||||
*/
|
||||
@Experimental
|
||||
|
@ -5,22 +5,18 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
/**
|
||||
* Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
|
||||
* Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature).
|
||||
* This can contain additional methods and or constructors.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* RecordBody ::= "{" ( {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}
|
||||
* | {@linkplain ASTClassOrInterfaceBodyDeclaration ClassOrInterfaceBodyDeclaration} )*
|
||||
* "}"
|
||||
* RecordBody ::= "{" ( {@linkplain ASTCompactConstructorDeclaration CompactConstructorDeclaration}
|
||||
* | {@linkplain ASTClassOrInterfaceBodyDeclaration ClassOrInterfaceBodyDeclaration} )* "}"
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTRecordBody extends ASTTypeBody {
|
||||
ASTRecordBody(int id) {
|
||||
super(id);
|
||||
|
@ -5,13 +5,12 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.VariableIdOwner;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
|
||||
|
||||
/**
|
||||
* Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
|
||||
* Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature).
|
||||
*
|
||||
* <p>The varargs ellipsis {@code "..."} is parsed as an {@linkplain ASTArrayTypeDim array dimension}
|
||||
* in the type node.
|
||||
@ -35,7 +34,6 @@ import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTRecordComponent extends AbstractJavaNode implements AccessNode, VariableIdOwner {
|
||||
|
||||
ASTRecordComponent(int id) {
|
||||
|
@ -5,13 +5,12 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTList.ASTMaybeEmptyListOf;
|
||||
import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.AllChildrenAreOfType;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
|
||||
|
||||
/**
|
||||
* Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
|
||||
* Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature).
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
@ -19,13 +18,11 @@ import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTRecordComponentList extends ASTMaybeEmptyListOf<ASTRecordComponent>
|
||||
implements SymbolDeclaratorNode, AllChildrenAreOfType<ASTRecordComponent> {
|
||||
|
||||
private JConstructorSymbol symbol;
|
||||
|
||||
|
||||
ASTRecordComponentList(int id) {
|
||||
super(id, ASTRecordComponent.class);
|
||||
}
|
||||
|
@ -7,12 +7,11 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
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 and JDK 15 preview feature).
|
||||
* A record declaration is a special data class type (JDK 16 feature).
|
||||
* This is a {@linkplain Node#isFindBoundary() find boundary} for tree traversal methods.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
@ -27,9 +26,8 @@ import net.sourceforge.pmd.lang.ast.NodeStream;
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://openjdk.java.net/jeps/384">JEP 384: Records (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/395">JEP 395: Records</a>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration {
|
||||
ASTRecordDeclaration(int id) {
|
||||
super(id);
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A type pattern (JDK16). This can be found on
|
||||
* the right-hand side of an {@link ASTInfixExpression InstanceOfExpression},
|
||||
* in a {@link ASTPatternExpression PatternExpression}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* TypePattern ::= ( "final" | {@linkplain ASTAnnotation Annotation} )* {@linkplain ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://openjdk.java.net/jeps/394">JEP 394: Pattern Matching for instanceof</a>
|
||||
*/
|
||||
public final class ASTTypePattern extends AbstractJavaNode implements ASTPattern {
|
||||
|
||||
private boolean isFinal;
|
||||
|
||||
ASTTypePattern(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type against which the expression is tested.
|
||||
*/
|
||||
public ASTType getTypeNode() {
|
||||
return getFirstChildOfType(ASTType.class);
|
||||
}
|
||||
|
||||
/** Returns the declared variable. */
|
||||
public ASTVariableDeclaratorId getVarId() {
|
||||
return getFirstChildOfType(ASTVariableDeclaratorId.class);
|
||||
}
|
||||
|
||||
void setFinal(boolean isFinal) {
|
||||
this.isFinal = isFinal;
|
||||
}
|
||||
|
||||
boolean isFinal() {
|
||||
return isFinal;
|
||||
}
|
||||
}
|
@ -1,45 +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.Experimental;
|
||||
|
||||
/**
|
||||
* A type test pattern (JDK 14 preview feature). This can be found on
|
||||
* the right-hand side of an {@link ASTInfixExpression InstanceOfExpression},
|
||||
* in a {@link ASTPatternExpression PatternExpression}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* TypeTestPattern ::= {@linkplain ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTTypeTestPattern extends AbstractJavaNode implements ASTPattern {
|
||||
|
||||
|
||||
ASTTypeTestPattern(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type against which the expression is tested.
|
||||
*/
|
||||
public ASTType getTypeNode() {
|
||||
return (ASTType) getChild(0);
|
||||
}
|
||||
|
||||
/** Returns the declared variable. */
|
||||
public ASTVariableDeclaratorId getVarId() {
|
||||
return (ASTVariableDeclaratorId) getChild(1);
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,6 @@ import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
|
||||
@ -112,7 +111,7 @@ public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator
|
||||
JavaNode parent = getParent();
|
||||
if (parent instanceof ASTVariableDeclarator) {
|
||||
return (AccessNode) parent.getParent();
|
||||
} else if (parent instanceof ASTTypeTestPattern) {
|
||||
} else if (parent instanceof ASTTypePattern) {
|
||||
return this; // this is pretty weird
|
||||
}
|
||||
return (AccessNode) parent;
|
||||
@ -239,7 +238,6 @@ public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator
|
||||
* Returns true if this is a binding variable in a
|
||||
* {@linkplain ASTPattern pattern}.
|
||||
*/
|
||||
@Experimental
|
||||
public boolean isPatternBinding() {
|
||||
return getParent() instanceof ASTPattern;
|
||||
}
|
||||
|
@ -339,8 +339,8 @@ final class LazyTypeResolver extends JavaVisitorBase<Void, @NonNull JTypeMirror>
|
||||
@Override
|
||||
public JTypeMirror visit(ASTPatternExpression node, Void data) {
|
||||
ASTPattern pattern = node.getPattern();
|
||||
if (pattern instanceof ASTTypeTestPattern) {
|
||||
return ((ASTTypeTestPattern) pattern).getTypeNode().getTypeMirror();
|
||||
if (pattern instanceof ASTTypePattern) {
|
||||
return ((ASTTypePattern) pattern).getTypeNode().getTypeMirror();
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown pattern " + pattern);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeArguments;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeTestPattern;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypePattern;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTYieldStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.JModifier;
|
||||
@ -110,21 +110,79 @@ public class LanguageLevelChecker<T> {
|
||||
|
||||
/** Those are just for the preview features. */
|
||||
private enum PreviewFeature implements LanguageFeature {
|
||||
/**
|
||||
* Note: Withdrawn with JEP 354, yield statement is used instead.
|
||||
* @see #YIELD_STATEMENTS
|
||||
* @see <a href="https://openjdk.java.net/jeps/325">JEP 325: Switch Expressions (Preview)</a>
|
||||
*/
|
||||
BREAK__WITH__VALUE_STATEMENTS(12, 12, false),
|
||||
|
||||
/**
|
||||
* @see <a href="https://openjdk.java.net/jeps/325">JEP 325: Switch Expressions (Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/354">JEP 354: Switch Expressions (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/361">JEP 361: Switch Expressions</a>
|
||||
*/
|
||||
COMPOSITE_CASE_LABEL(12, 13, true),
|
||||
/**
|
||||
* @see <a href="https://openjdk.java.net/jeps/325">JEP 325: Switch Expressions (Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/354">JEP 354: Switch Expressions (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/361">JEP 361: Switch Expressions</a>
|
||||
*/
|
||||
SWITCH_EXPRESSIONS(12, 13, true),
|
||||
/**
|
||||
* @see <a href="https://openjdk.java.net/jeps/325">JEP 325: Switch Expressions (Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/354">JEP 354: Switch Expressions (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/361">JEP 361: Switch Expressions</a>
|
||||
*/
|
||||
SWITCH_RULES(12, 13, true),
|
||||
|
||||
TEXT_BLOCK_LITERALS(13, 14, true),
|
||||
/**
|
||||
* @see #SWITCH_EXPRESSIONS
|
||||
* @see <a href="https://openjdk.java.net/jeps/354">JEP 354: Switch Expressions (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/361">JEP 361: Switch Expressions</a>
|
||||
*/
|
||||
YIELD_STATEMENTS(13, 13, true),
|
||||
|
||||
/** \s */
|
||||
/**
|
||||
* @see <a href="https://openjdk.java.net/jeps/355">JEP 355: Text Blocks (Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/368">JEP 368: Text Blocks (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/378">JEP 378: Text Blocks</a>
|
||||
*/
|
||||
TEXT_BLOCK_LITERALS(13, 14, true),
|
||||
/**
|
||||
* The new escape sequence {@code \s} simply translates to a single space {@code \u0020}.
|
||||
*
|
||||
* @see #TEXT_BLOCK_LITERALS
|
||||
* @see <a href="https://openjdk.java.net/jeps/368">JEP 368: Text Blocks (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/378">JEP 378: Text Blocks</a>
|
||||
*/
|
||||
SPACE_STRING_ESCAPES(14, 14, true),
|
||||
RECORD_DECLARATIONS(14, 15, false),
|
||||
TYPE_TEST_PATTERNS_IN_INSTANCEOF(14, 15, false),
|
||||
SEALED_CLASSES(15, 15, false),
|
||||
STATIC_LOCAL_TYPE_DECLARATIONS(15, 15, false), // part of the sealed classes JEP
|
||||
|
||||
/**
|
||||
* @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>
|
||||
* @see <a href="https://openjdk.java.net/jeps/395">JEP 395: Records</a>
|
||||
*/
|
||||
RECORD_DECLARATIONS(14, 15, true),
|
||||
|
||||
/**
|
||||
* @see <a href="https://openjdk.java.net/jeps/305">JEP 305: Pattern Matching for instanceof (Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/375">JEP 375: Pattern Matching for instanceof (Second Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/394">JEP 394: Pattern Matching for instanceof</a>
|
||||
*/
|
||||
TYPE_PATTERNS_IN_INSTANCEOF(14, 15, true),
|
||||
|
||||
/**
|
||||
* Part of the records JEP 394.
|
||||
* @see #RECORD_DECLARATIONS
|
||||
* @see <a href="https://bugs.openjdk.java.net/browse/JDK-8253374">JLS changes for Static Members of Inner Classes</a>
|
||||
*/
|
||||
STATIC_LOCAL_TYPE_DECLARATIONS(15, 15, true),
|
||||
|
||||
/**
|
||||
* @see <a href="https://openjdk.java.net/jeps/360">JEP 360: Sealed Classes (Preview)</a>
|
||||
* @see <a href="https://openjdk.java.net/jeps/397">JEP 397: Sealed Classes (Second Preview)</a>
|
||||
*/
|
||||
SEALED_CLASSES(15, 16, false),
|
||||
|
||||
; // SUPPRESS CHECKSTYLE enum trailing semi is awesome
|
||||
|
||||
@ -164,18 +222,37 @@ public class LanguageLevelChecker<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/** Those use a max valid version. */
|
||||
private enum ReservedIdentifiers implements LanguageFeature {
|
||||
/**
|
||||
* Those use a max valid version.
|
||||
*
|
||||
* @see <a href="http://cr.openjdk.java.net/~gbierman/jep397/jep397-20201204/specs/contextual-keywords-jls.html">Contextual Keywords</a>
|
||||
*/
|
||||
private enum Keywords implements LanguageFeature {
|
||||
/**
|
||||
* ReservedKeyword since Java 1.4.
|
||||
*/
|
||||
ASSERT_AS_AN_IDENTIFIER(4, "assert"),
|
||||
/**
|
||||
* ReservedKeyword since Java 1.5.
|
||||
*/
|
||||
ENUM_AS_AN_IDENTIFIER(5, "enum"),
|
||||
/**
|
||||
* ReservedKeyword since Java 9.
|
||||
*/
|
||||
UNDERSCORE_AS_AN_IDENTIFIER(9, "_"),
|
||||
/**
|
||||
* ContextualKeyword since Java 10.
|
||||
*/
|
||||
VAR_AS_A_TYPE_NAME(10, "var"),
|
||||
// yield -> PreviewFeature.YIELD_STATEMENTS
|
||||
RECORD_AS_A_TYPE_NAME(14, "record");
|
||||
// sealed -> PreviewFeature.SEALED_CLASSES
|
||||
// permits -> PreviewFeature.SEALED_CLASSES
|
||||
|
||||
private final int maxJdkVersion;
|
||||
private final String reserved;
|
||||
|
||||
ReservedIdentifiers(int minJdkVersion, String reserved) {
|
||||
Keywords(int minJdkVersion, String reserved) {
|
||||
this.maxJdkVersion = minJdkVersion;
|
||||
this.reserved = reserved;
|
||||
}
|
||||
@ -411,8 +488,8 @@ public class LanguageLevelChecker<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ASTTypeTestPattern node, T data) {
|
||||
check(node, PreviewFeature.TYPE_TEST_PATTERNS_IN_INSTANCEOF, data);
|
||||
public Void visit(ASTTypePattern node, T data) {
|
||||
check(node, PreviewFeature.TYPE_PATTERNS_IN_INSTANCEOF, data);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -484,9 +561,9 @@ public class LanguageLevelChecker<T> {
|
||||
}
|
||||
String simpleName = node.getSimpleName();
|
||||
if ("var".equals(simpleName)) {
|
||||
check(node, ReservedIdentifiers.VAR_AS_A_TYPE_NAME, data);
|
||||
check(node, Keywords.VAR_AS_A_TYPE_NAME, data);
|
||||
} else if ("record".equals(simpleName)) {
|
||||
check(node, ReservedIdentifiers.RECORD_AS_A_TYPE_NAME, data);
|
||||
check(node, Keywords.RECORD_AS_A_TYPE_NAME, data);
|
||||
}
|
||||
checkIdent(node, simpleName, data);
|
||||
return null;
|
||||
@ -494,11 +571,11 @@ public class LanguageLevelChecker<T> {
|
||||
|
||||
private void checkIdent(JavaNode node, String simpleName, T acc) {
|
||||
if ("enum".equals(simpleName)) {
|
||||
check(node, ReservedIdentifiers.ENUM_AS_AN_IDENTIFIER, acc);
|
||||
check(node, Keywords.ENUM_AS_AN_IDENTIFIER, acc);
|
||||
} else if ("assert".equals(simpleName)) {
|
||||
check(node, ReservedIdentifiers.ASSERT_AS_AN_IDENTIFIER, acc);
|
||||
check(node, Keywords.ASSERT_AS_AN_IDENTIFIER, acc);
|
||||
} else if ("_".equals(simpleName)) {
|
||||
check(node, ReservedIdentifiers.UNDERSCORE_AS_AN_IDENTIFIER, acc);
|
||||
check(node, Keywords.UNDERSCORE_AS_AN_IDENTIFIER, acc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompactConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFieldAccess;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
|
||||
@ -26,7 +27,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodReference;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTRecordConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableAccess;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.AccessNode;
|
||||
@ -70,7 +70,7 @@ public final class JavaDesignerBindings extends DefaultDesignerBindings {
|
||||
} else if (node instanceof ASTMethodDeclaration) {
|
||||
return TreeIconId.METHOD;
|
||||
} else if (node instanceof ASTConstructorDeclaration
|
||||
|| node instanceof ASTRecordConstructorDeclaration) {
|
||||
|| node instanceof ASTCompactConstructorDeclaration) {
|
||||
return TreeIconId.CONSTRUCTOR;
|
||||
} else if (node instanceof ASTVariableDeclaratorId) {
|
||||
return TreeIconId.VARIABLE;
|
||||
|
@ -61,5 +61,4 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCatchClause;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompactConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
|
||||
@ -40,7 +41,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTLocalClassStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTModifierList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTRecordConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTResource;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTResourceList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
|
||||
@ -299,7 +299,7 @@ public final class SymbolTableResolver {
|
||||
|
||||
|
||||
@Override
|
||||
public Void visit(ASTRecordConstructorDeclaration node, @NonNull ReferenceCtx ctx) {
|
||||
public Void visit(ASTCompactConstructorDeclaration node, @NonNull ReferenceCtx ctx) {
|
||||
setTopSymbolTable(node.getModifiers());
|
||||
int pushed = pushOnStack(f.recordCtor(top(), enclosing(), node.getSymbol()));
|
||||
setTopSymbolTableAndRecurse(node, ctx);
|
||||
|
@ -24,6 +24,7 @@ import net.sourceforge.pmd.annotation.InternalApi;
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class PMDASMVisitor extends ClassVisitor {
|
||||
private static final int ASM_API = Opcodes.ASM9; // latest, non-experimental API version
|
||||
|
||||
private String outerName;
|
||||
|
||||
@ -40,7 +41,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
public List<String> innerClasses;
|
||||
|
||||
public PMDASMVisitor(String outerName) {
|
||||
super(Opcodes.ASM9);
|
||||
super(ASM_API);
|
||||
this.outerName = outerName;
|
||||
}
|
||||
|
||||
@ -181,7 +182,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDFieldVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM9);
|
||||
super(ASM_API);
|
||||
parent = visitor;
|
||||
}
|
||||
|
||||
@ -196,7 +197,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDAnnotationVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM9);
|
||||
super(ASM_API);
|
||||
parent = visitor;
|
||||
}
|
||||
|
||||
@ -228,7 +229,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDSignatureVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM9);
|
||||
super(ASM_API);
|
||||
this.parent = visitor;
|
||||
}
|
||||
|
||||
@ -292,7 +293,7 @@ public class PMDASMVisitor extends ClassVisitor {
|
||||
private PMDASMVisitor parent;
|
||||
|
||||
PMDMethodVisitor(PMDASMVisitor visitor) {
|
||||
super(Opcodes.ASM9);
|
||||
super(ASM_API);
|
||||
parent = visitor;
|
||||
}
|
||||
|
||||
|
@ -19,15 +19,27 @@ public class LanguageVersionDiscovererTest {
|
||||
|
||||
/**
|
||||
* Test on Java file with default options.
|
||||
* Always the latest non-preview version will be the default version.
|
||||
*/
|
||||
@Test
|
||||
public void testJavaFileUsingDefaults() {
|
||||
LanguageVersionDiscoverer discoverer = new LanguageVersionDiscoverer();
|
||||
File javaFile = new File("/path/to/MyClass.java");
|
||||
|
||||
LanguageVersion latest = determineLatestNonPreviewVersion();
|
||||
|
||||
LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile);
|
||||
assertEquals("LanguageVersion must be Java 15 !",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), languageVersion);
|
||||
assertEquals("Latest language version must be default", latest, languageVersion);
|
||||
}
|
||||
|
||||
private LanguageVersion determineLatestNonPreviewVersion() {
|
||||
LanguageVersion latest = null;
|
||||
for (LanguageVersion lv : LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersions()) {
|
||||
if (!lv.getName().endsWith("preview")) {
|
||||
latest = lv;
|
||||
}
|
||||
}
|
||||
return latest;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,7 +60,7 @@ public class LanguageVersionDiscovererTest {
|
||||
public void testLanguageVersionDiscoverer() {
|
||||
PMDConfiguration configuration = new PMDConfiguration();
|
||||
LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer();
|
||||
assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"),
|
||||
assertEquals("Default Java version", determineLatestNonPreviewVersion(),
|
||||
languageVersionDiscoverer
|
||||
.getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME)));
|
||||
configuration
|
||||
|
@ -53,9 +53,13 @@ public class LanguageVersionTest extends AbstractLanguageVersionTest {
|
||||
{ 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"), },
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), },
|
||||
{ JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "15-preview",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15-preview"), },
|
||||
{ JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "16",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("16"), },
|
||||
{ JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "16-preview",
|
||||
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("16-preview"), },
|
||||
|
||||
// this one won't be found: case sensitive!
|
||||
{ "JAVA", "JAVA", "1.7", null, },
|
||||
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
|
||||
|
||||
/**
|
||||
* Tests new java14 preview features.
|
||||
*/
|
||||
public class Java14PreviewTest {
|
||||
private final JavaParsingHelper java14 =
|
||||
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14")
|
||||
.withResourceContext(getClass(), "jdkversiontests/java14/");
|
||||
|
||||
private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview");
|
||||
private final JavaParsingHelper java13 = java14.withDefaultVersion("13");
|
||||
|
||||
@Test
|
||||
public void textBlocks() {
|
||||
ASTCompilationUnit compilationUnit = java14p.parseResource("TextBlocks.java");
|
||||
List<ASTStringLiteral> literals = compilationUnit.findDescendantsOfType(ASTStringLiteral.class);
|
||||
Assert.assertEquals(22, literals.size());
|
||||
Assert.assertFalse(literals.get(2).isTextBlock());
|
||||
Assert.assertFalse(literals.get(12).isTextBlock());
|
||||
Assert.assertFalse(literals.get(17).isTextBlock());
|
||||
Assert.assertFalse(literals.get(18).isTextBlock());
|
||||
Assert.assertFalse(literals.get(20).isTextBlock());
|
||||
Assert.assertFalse(literals.get(21).isTextBlock());
|
||||
|
||||
List<ASTStringLiteral> textBlocks = new ArrayList<>();
|
||||
for (ASTStringLiteral literal : literals) {
|
||||
if (literal.isTextBlock()) {
|
||||
textBlocks.add(literal);
|
||||
}
|
||||
}
|
||||
Assert.assertEquals(16, textBlocks.size());
|
||||
Assert.assertEquals("\"\"\"\n"
|
||||
+ " <html> \n"
|
||||
+ " <body>\n"
|
||||
+ " <p>Hello, world</p> \n"
|
||||
+ " </body> \n"
|
||||
+ " </html> \n"
|
||||
+ " \"\"\"",
|
||||
textBlocks.get(0).getImage());
|
||||
Assert.assertEquals("<html>\n"
|
||||
+ " <body>\n"
|
||||
+ " <p>Hello, world</p>\n"
|
||||
+ " </body>\n"
|
||||
+ "</html>\n", textBlocks.get(0).getConstValue());
|
||||
|
||||
// Note: More tests are in ASTLiteralTest.
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void textBlocksBeforeJava14PreviewShouldFail() {
|
||||
java13.parseResource("TextBlocks.java");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void stringEscapeSequenceShouldFail() {
|
||||
java14.parse("class Foo { String s =\"a\\sb\"; }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recordPoint() {
|
||||
ASTCompilationUnit compilationUnit = java14p.parseResource("Point.java");
|
||||
ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class);
|
||||
Assert.assertEquals("Point", recordDecl.getImage());
|
||||
Assert.assertFalse(recordDecl.isNested());
|
||||
List<ASTRecordComponent> components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class)
|
||||
.findChildrenOfType(ASTRecordComponent.class);
|
||||
Assert.assertEquals(2, components.size());
|
||||
Assert.assertEquals("x", components.get(0).getVarId().getImage());
|
||||
Assert.assertEquals("y", components.get(1).getVarId().getImage());
|
||||
// TODO: type resolution for record components
|
||||
// Assert.assertNull(components.get(0).getVarId().getNameDeclaration().getAccessNodeParent());
|
||||
// Assert.assertEquals(Integer.TYPE, components.get(0).getVarId().getNameDeclaration().getType());
|
||||
// Assert.assertEquals("int", components.get(0).getVarId().getNameDeclaration().getTypeImage());
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordPointBeforeJava14PreviewShouldFail() {
|
||||
java14.parseResource("Point.java");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordCtorWithThrowsShouldFail() {
|
||||
java14p.parse(" record R {"
|
||||
+ " R throws IOException {}"
|
||||
+ " }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void innerRecords() {
|
||||
ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java");
|
||||
List<ASTRecordDeclaration> recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class, true);
|
||||
Assert.assertEquals(7, recordDecls.size());
|
||||
|
||||
ASTRecordDeclaration complex = recordDecls.get(0);
|
||||
Assert.assertEquals("MyComplex", complex.getSimpleName());
|
||||
Assert.assertTrue(complex.isNested());
|
||||
Assert.assertEquals(0, getComponent(complex, 0).getDeclaredAnnotations().count());
|
||||
Assert.assertEquals(1, getComponent(complex, 1).getDeclaredAnnotations().count());
|
||||
Assert.assertEquals(2, complex.getDeclarations().count());
|
||||
Assert.assertTrue(complex.getDeclarations().get(0) instanceof ASTConstructorDeclaration);
|
||||
Assert.assertTrue(complex.getDeclarations().get(1) instanceof ASTRecordDeclaration);
|
||||
|
||||
ASTRecordDeclaration nested = recordDecls.get(1);
|
||||
Assert.assertEquals("Nested", nested.getSimpleName());
|
||||
Assert.assertTrue(nested.isNested());
|
||||
|
||||
ASTRecordDeclaration range = recordDecls.get(2);
|
||||
Assert.assertEquals("Range", range.getSimpleName());
|
||||
Assert.assertEquals(2, range.getRecordComponents().size());
|
||||
List<ASTRecordConstructorDeclaration> 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.getRecordComponents().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.getRecordComponents().getChild(index);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordIsARestrictedIdentifier() {
|
||||
java14p.parse("public class record {}");
|
||||
}
|
||||
}
|
@ -27,7 +27,6 @@ public class Java14Test {
|
||||
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14")
|
||||
.withResourceContext(Java14Test.class, "jdkversiontests/java14/");
|
||||
|
||||
private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview");
|
||||
private final JavaParsingHelper java13 = java14.withDefaultVersion("13");
|
||||
|
||||
/**
|
||||
@ -36,7 +35,6 @@ public class Java14Test {
|
||||
@Test
|
||||
public void switchExpressions() {
|
||||
parseAndCheckSwitchExpression(java14);
|
||||
parseAndCheckSwitchExpression(java14p);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,7 +133,6 @@ public class Java14Test {
|
||||
@Test
|
||||
public void multipleCaseLabels() {
|
||||
multipleCaseLabels(java14);
|
||||
multipleCaseLabels(java14p);
|
||||
}
|
||||
|
||||
private void multipleCaseLabels(JavaParsingHelper parser) {
|
||||
@ -150,7 +147,6 @@ public class Java14Test {
|
||||
@Test
|
||||
public void switchRules() {
|
||||
switchRules(java14);
|
||||
switchRules(java14p);
|
||||
}
|
||||
|
||||
private void switchRules(JavaParsingHelper parser) {
|
||||
@ -177,7 +173,6 @@ public class Java14Test {
|
||||
@Test
|
||||
public void simpleSwitchExpressions() {
|
||||
simpleSwitchExpressions(java14);
|
||||
simpleSwitchExpressions(java14p);
|
||||
}
|
||||
|
||||
private void simpleSwitchExpressions(JavaParsingHelper parser) {
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 Java16PreviewTreeDumpTest extends BaseTreeDumpTest {
|
||||
private final JavaParsingHelper java16p =
|
||||
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("16-preview")
|
||||
.withResourceContext(Java16PreviewTreeDumpTest.class, "jdkversiontests/java16p/");
|
||||
private final JavaParsingHelper java16 = java16p.withDefaultVersion("16");
|
||||
|
||||
public Java16PreviewTreeDumpTest() {
|
||||
super(new RelevantAttributePrinter(), ".java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseParsingHelper<?, ?> getParser() {
|
||||
return java16p;
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void sealedClassBeforeJava16Preview() {
|
||||
java16.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() {
|
||||
java16.parseResource("expression/Expr.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sealedInterface() {
|
||||
doTest("expression/Expr");
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 Java16TreeDumpTest extends BaseTreeDumpTest {
|
||||
private final JavaParsingHelper java16 =
|
||||
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("16")
|
||||
.withResourceContext(Java15TreeDumpTest.class, "jdkversiontests/java16/");
|
||||
private final JavaParsingHelper java16p = java16.withDefaultVersion("16-preview");
|
||||
private final JavaParsingHelper java15 = java16.withDefaultVersion("15");
|
||||
|
||||
public Java16TreeDumpTest() {
|
||||
super(new RelevantAttributePrinter(), ".java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseParsingHelper<?, ?> getParser() {
|
||||
return java16;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patternMatchingInstanceof() {
|
||||
doTest("PatternMatchingInstanceof");
|
||||
|
||||
// extended tests for type resolution etc.
|
||||
ASTCompilationUnit compilationUnit = java16.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 patternMatchingInstanceofBeforeJava16ShouldFail() {
|
||||
java15.parseResource("PatternMatchingInstanceof.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localClassAndInterfaceDeclarations() {
|
||||
doTest("LocalClassAndInterfaceDeclarations");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void localClassAndInterfaceDeclarationsBeforeJava16ShouldFail() {
|
||||
java15.parseResource("LocalClassAndInterfaceDeclarations.java");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void localAnnotationsAreNotAllowed() {
|
||||
java16.parse("public class Foo { { @interface MyLocalAnnotation {} } }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localRecords() {
|
||||
doTest("LocalRecords");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recordPoint() {
|
||||
doTest("Point");
|
||||
|
||||
// extended tests for type resolution etc.
|
||||
ASTCompilationUnit compilationUnit = java16.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 recordPointBeforeJava16ShouldFail() {
|
||||
java15.parseResource("Point.java");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordCtorWithThrowsShouldFail() {
|
||||
java16.parse(" record R {"
|
||||
+ " R throws IOException {}"
|
||||
+ " }");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordMustNotExtend() {
|
||||
java16.parse("record RecordEx(int x) extends Number { }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void innerRecords() {
|
||||
doTest("Records");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void recordIsARestrictedIdentifier() {
|
||||
java16.parse("public class record {}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sealedAndNonSealedIdentifiers() {
|
||||
doTest("NonSealedIdentifier");
|
||||
java16p.parseResource("NonSealedIdentifier.java"); // make sure we can parse it with preview as well
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ class ASTLiteralTest : ParserTestSpec({
|
||||
}
|
||||
}
|
||||
|
||||
parserTest("Text block literal", javaVersions = since(J14__PREVIEW)) {
|
||||
parserTest("Text block literal", javaVersions = since(J15__PREVIEW)) {
|
||||
|
||||
val delim = "\"\"\""
|
||||
|
||||
|
@ -6,25 +6,24 @@ package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import io.kotest.matchers.shouldBe
|
||||
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 net.sourceforge.pmd.lang.ast.test.shouldBe as typeShouldBe
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.*
|
||||
import java.io.IOException
|
||||
|
||||
class ASTPatternTest : ParserTestSpec({
|
||||
|
||||
parserTest("Test patterns only available on JDK 14+15 (preview)", javaVersions = JavaVersion.except(J14__PREVIEW, J15__PREVIEW)) {
|
||||
val typePatternsVersions = JavaVersion.since(J16).plus(J15__PREVIEW)
|
||||
|
||||
parserTest("Test patterns only available on JDK 15 (preview) and JDK16 and JDK16 (preview)", javaVersions = typePatternsVersions) {
|
||||
|
||||
inContext(ExpressionParsingCtx) {
|
||||
"obj instanceof Class c" should throwParseException {
|
||||
it.message.shouldContain("Type test patterns in instanceof is a preview feature of JDK")
|
||||
it.message.shouldContain("Type patterns in instanceof was only standardized in Java 16")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parserTest("Test simple patterns", javaVersions = listOf(J14__PREVIEW, J15__PREVIEW)) {
|
||||
parserTest("Test simple patterns", javaVersions = typePatternsVersions) {
|
||||
|
||||
importedTypes += IOException::class.java
|
||||
inContext(ExpressionParsingCtx) {
|
||||
@ -33,11 +32,50 @@ class ASTPatternTest : ParserTestSpec({
|
||||
infixExpr(BinaryOp.INSTANCEOF) {
|
||||
variableAccess("obj")
|
||||
child<ASTPatternExpression> {
|
||||
it::getPattern shouldBe child<ASTTypeTestPattern> {
|
||||
//it.isAnnotationPresent("java.lang.Deprecated") shouldBe false
|
||||
it::getPattern shouldBe child<ASTTypePattern> {
|
||||
it::getTypeNode shouldBe classType("Class")
|
||||
it::getVarId shouldBe variableId("c") {
|
||||
it::getModifiers shouldBe modifiers { } // dummy modifier list
|
||||
it.hasExplicitModifiers(JModifier.FINAL) shouldBe false
|
||||
it.hasModifiers(JModifier.FINAL) shouldBe false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"obj instanceof final Class c" should parseAs {
|
||||
infixExpr(BinaryOp.INSTANCEOF) {
|
||||
variableAccess("obj")
|
||||
child<ASTPatternExpression> {
|
||||
//it.isAnnotationPresent("java.lang.Deprecated") shouldBe false
|
||||
it::getPattern shouldBe child<ASTTypePattern> {
|
||||
it::getTypeNode shouldBe classType("Class")
|
||||
it::getVarId shouldBe variableId("c") {
|
||||
it::getModifiers shouldBe modifiers { } // dummy modifier list
|
||||
it.hasExplicitModifiers(JModifier.FINAL) shouldBe true
|
||||
it.hasModifiers(JModifier.FINAL) shouldBe true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"obj instanceof @Deprecated Class c" should parseAs {
|
||||
infixExpr(BinaryOp.INSTANCEOF) {
|
||||
variableAccess("obj")
|
||||
child<ASTPatternExpression> {
|
||||
child<ASTAnnotation>(ignoreChildren = true) {
|
||||
it.annotationName shouldBe "Deprecated"
|
||||
}
|
||||
|
||||
//it.isAnnotationPresent("java.lang.Deprecated") shouldBe true
|
||||
it::getPattern shouldBe child<ASTTypePattern> {
|
||||
it::getTypeNode shouldBe classType("Class")
|
||||
it::getVarId shouldBe variableId("c") {
|
||||
it::getModifiers shouldBe modifiers { } // dummy modifier list
|
||||
it.hasExplicitModifiers(JModifier.FINAL) shouldBe true
|
||||
it.hasModifiers(JModifier.FINAL) shouldBe true
|
||||
}
|
||||
}
|
||||
@ -46,6 +84,4 @@ class ASTPatternTest : ParserTestSpec({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
@ -33,8 +33,9 @@ enum class JavaVersion : Comparable<JavaVersion> {
|
||||
J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11,
|
||||
J12,
|
||||
J13,
|
||||
J14, J14__PREVIEW,
|
||||
J15, J15__PREVIEW;
|
||||
J14,
|
||||
J15, J15__PREVIEW,
|
||||
J16, J16__PREVIEW;
|
||||
|
||||
/** Name suitable for use with e.g. [JavaParsingHelper.parse] */
|
||||
val pmdName: String = name.removePrefix("J").replaceFirst("__", "-").replace('_', '.').toLowerCase()
|
||||
|
@ -1,113 +0,0 @@
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
/**
|
||||
* @see <a href="https://openjdk.java.net/jeps/368">JEP 368: Text Blocks (Second Preview)</a>
|
||||
*/
|
||||
public class TextBlocks {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// note: there is trailing whitespace!!
|
||||
String html = """
|
||||
<html>
|
||||
<body>
|
||||
<p>Hello, world</p>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
System.out.println(html);
|
||||
|
||||
String query = """
|
||||
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
|
||||
WHERE `CITY` = 'INDIANAPOLIS'
|
||||
ORDER BY `EMP_ID`, `LAST_NAME`;
|
||||
""";
|
||||
System.out.println(query);
|
||||
|
||||
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
|
||||
Object obj = engine.eval("""
|
||||
function hello() {
|
||||
print('"Hello, world"');
|
||||
}
|
||||
|
||||
hello();
|
||||
""");
|
||||
|
||||
// Escape sequences
|
||||
String htmlWithEscapes = """
|
||||
<html>\r
|
||||
<body>\r
|
||||
<p>Hello, world</p>\r
|
||||
</body>\r
|
||||
</html>\r
|
||||
""";
|
||||
System.out.println(htmlWithEscapes);
|
||||
|
||||
String season = """
|
||||
winter"""; // the six characters w i n t e r
|
||||
|
||||
String period = """
|
||||
winter
|
||||
"""; // the seven characters w i n t e r LF
|
||||
|
||||
String greeting =
|
||||
"""
|
||||
Hi, "Bob"
|
||||
"""; // the ten characters H i , SP " B o b " LF
|
||||
|
||||
String salutation =
|
||||
"""
|
||||
Hi,
|
||||
"Bob"
|
||||
"""; // the eleven characters H i , LF SP " B o b " LF
|
||||
|
||||
String empty = """
|
||||
"""; // the empty string (zero length)
|
||||
|
||||
String quote = """
|
||||
"
|
||||
"""; // the two characters " LF
|
||||
|
||||
String backslash = """
|
||||
\\
|
||||
"""; // the two characters \ LF
|
||||
|
||||
String normalStringLiteral = "test";
|
||||
|
||||
String code =
|
||||
"""
|
||||
String text = \"""
|
||||
A text block inside a text block
|
||||
\""";
|
||||
""";
|
||||
|
||||
// new escape sequences
|
||||
String text = """
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing \
|
||||
elit, sed do eiusmod tempor incididunt ut labore \
|
||||
et dolore magna aliqua.\
|
||||
""";
|
||||
System.out.println(text);
|
||||
|
||||
String colors = """
|
||||
red \s
|
||||
green\s
|
||||
blue \s
|
||||
""";
|
||||
System.out.println(colors);
|
||||
|
||||
// empty new line as first content
|
||||
String emptyLine = """
|
||||
|
||||
test
|
||||
""";
|
||||
System.out.println(emptyLine.replaceAll("\n", "<LF>"));
|
||||
|
||||
// backslash escapes
|
||||
String bs = """
|
||||
\\test
|
||||
""";
|
||||
System.out.println(bs.replaceAll("\n", "<LF>"));
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ public class LocalInterfacesAndEnums {
|
||||
|
||||
enum MyLocalEnum { A }
|
||||
|
||||
@interface MyLocalAnnotation {}
|
||||
// not supported anymore with Java16
|
||||
//@interface MyLocalAnnotation {}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user