Fix merge wip
This commit is contained in:
@ -951,8 +951,8 @@ void ModifierList():
|
||||
| "volatile" { modifiers.add(JModifier.VOLATILE); }
|
||||
| "strictfp" { modifiers.add(JModifier.STRICTFP); }
|
||||
| "default" { modifiers.add(JModifier.DEFAULT); }
|
||||
| LOOKAHEAD({isKeyword("sealed")}) <IDENTIFIER> { modifiers |= AccessNode.SEALED; }
|
||||
| LOOKAHEAD({isNonSealedModifier()}) <IDENTIFIER> <MINUS> <IDENTIFIER> { modifiers |= AccessNode.NON_SEALED; }
|
||||
| LOOKAHEAD({isKeyword("sealed")}) <IDENTIFIER> { modifiers.add(JModifier.SEALED); }
|
||||
| LOOKAHEAD({isNonSealedModifier()}) <IDENTIFIER> <MINUS> <IDENTIFIER> { modifiers.add(JModifier.NON_SEALED); }
|
||||
| Annotation()
|
||||
)
|
||||
)*
|
||||
@ -2162,7 +2162,7 @@ void Block() :
|
||||
}
|
||||
|
||||
void BlockStatement() #void:
|
||||
{int mods = 0;}
|
||||
{}
|
||||
{
|
||||
LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement()
|
||||
| LOOKAHEAD( { isYieldStart() } ) YieldStatement()
|
||||
@ -2171,34 +2171,14 @@ void BlockStatement() #void:
|
||||
// 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()
|
||||
ModifierList()
|
||||
(
|
||||
LOOKAHEAD({localTypeDeclLookahead()}) LocalTypeDecl(mods)
|
||||
LOOKAHEAD({localTypeDeclLookahead()}) LocalTypeDecl()
|
||||
|
|
||||
{
|
||||
List<ASTAnnotation> annotations = new ArrayList<ASTAnnotation>();
|
||||
while (jjtree.peekNode() instanceof ASTAnnotation) {
|
||||
annotations.add((ASTAnnotation) jjtree.popNode());
|
||||
}
|
||||
}
|
||||
LocalVariableDeclaration()
|
||||
{
|
||||
ASTLocalVariableDeclaration localVarDecl = (ASTLocalVariableDeclaration) jjtree.peekNode();
|
||||
if ((mods & AccessNode.FINAL) == AccessNode.FINAL) {
|
||||
localVarDecl.setFinal(true);
|
||||
}
|
||||
if (!annotations.isEmpty()) {
|
||||
Collections.reverse(annotations);
|
||||
for (ASTAnnotation a : annotations) {
|
||||
localVarDecl.insertChild(a, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
";"
|
||||
LocalVariableDeclaration() ";"
|
||||
)
|
||||
| LOOKAHEAD({classModifierLookahead() || localTypeDeclLookahead()})
|
||||
mods=Modifiers()
|
||||
LocalTypeDecl(mods)
|
||||
ModifierList() LocalTypeDecl()
|
||||
| LOOKAHEAD(Type() <IDENTIFIER>)
|
||||
LocalVariableDeclaration() ";" {
|
||||
// make it so that the LocalVariableDeclaration's last token is the semicolon
|
||||
@ -2214,16 +2194,13 @@ void BlockStatement() #void:
|
||||
Statement()
|
||||
}
|
||||
|
||||
void LocalTypeDecl(int mods) #LocalClassStatement:
|
||||
void LocalTypeDecl() #LocalClassStatement:
|
||||
{}
|
||||
{
|
||||
(
|
||||
LOOKAHEAD(<CLASS>) ClassOrInterfaceDeclaration(mods)
|
||||
| LOOKAHEAD(<INTERFACE>) ClassOrInterfaceDeclaration(mods)
|
||||
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration(mods)
|
||||
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(mods)
|
||||
| AnnotationTypeDeclaration(mods)
|
||||
)
|
||||
ClassOrInterfaceDeclaration()
|
||||
| AnnotationTypeDeclaration()
|
||||
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration()
|
||||
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration()
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4,12 +4,10 @@
|
||||
|
||||
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.lang.ast.Node;
|
||||
import net.sourceforge.pmd.util.CollectionUtil;
|
||||
|
||||
|
||||
/**
|
||||
@ -75,7 +73,7 @@ public final class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclara
|
||||
|
||||
@Experimental
|
||||
public List<ASTClassOrInterfaceType> getPermittedSubclasses() {
|
||||
return ASTList.orEmpty(children(ASTPermitsList.class));
|
||||
return ASTList.orEmpty(children(ASTPermitsList.class).first());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -167,6 +167,7 @@ public final class ASTModifierList extends AbstractJavaNode {
|
||||
private static final EffectiveModifierVisitor INSTANCE = new EffectiveModifierVisitor();
|
||||
|
||||
// TODO strictfp modifier is also implicitly given to descendants
|
||||
// TODO final modifier is implicitly given to direct subclasses of sealed interface/class
|
||||
|
||||
@Override
|
||||
public Void visit(ASTAnyTypeDeclaration node, Set<JModifier> effective) {
|
||||
|
@ -4,9 +4,8 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTList.ASTNonEmptyList;
|
||||
|
||||
|
||||
/**
|
||||
@ -23,19 +22,14 @@ import net.sourceforge.pmd.annotation.Experimental;
|
||||
* </pre>
|
||||
*/
|
||||
@Experimental
|
||||
public final class ASTPermitsList extends AbstractJavaNode implements Iterable<ASTClassOrInterfaceType> {
|
||||
public final class ASTPermitsList extends ASTNonEmptyList<ASTClassOrInterfaceType> {
|
||||
|
||||
ASTPermitsList(int id) {
|
||||
super(id);
|
||||
super(id, ASTClassOrInterfaceType.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ASTClassOrInterfaceType> iterator() {
|
||||
return children(ASTClassOrInterfaceType.class).iterator();
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
|
||||
|
||||
/**
|
||||
* A Java modifier. The ordering of constants respects the ordering
|
||||
* recommended by the JLS.
|
||||
@ -21,6 +23,11 @@ public enum JModifier {
|
||||
PROTECTED(Modifier.PROTECTED),
|
||||
PRIVATE(Modifier.PRIVATE),
|
||||
|
||||
/** Modifier {@code "sealed"} (preview feature of JDK 15). */
|
||||
SEALED(0),
|
||||
/** Modifier {@code "non-sealed"} (preview feature of JDK 15). */
|
||||
NON_SEALED("non-sealed", 0),
|
||||
|
||||
ABSTRACT(Modifier.ABSTRACT),
|
||||
STATIC(Modifier.STATIC),
|
||||
FINAL(Modifier.FINAL),
|
||||
@ -38,17 +45,34 @@ public enum JModifier {
|
||||
VOLATILE(Modifier.VOLATILE);
|
||||
|
||||
|
||||
private final String token = name().toLowerCase(Locale.ROOT);
|
||||
private final String token;
|
||||
private final int reflect;
|
||||
|
||||
JModifier(int reflect) {
|
||||
this.token = name().toLowerCase(Locale.ROOT);
|
||||
this.reflect = reflect;
|
||||
}
|
||||
|
||||
JModifier(String token, int reflect) {
|
||||
this.token = token;
|
||||
this.reflect = reflect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the constant of java.lang.reflect.Modifier that this
|
||||
* modifier corresponds to. Be aware that {@link #DEFAULT} has
|
||||
* no equivalent in {@link Modifier}.
|
||||
* modifier corresponds to. Be aware that the following constants
|
||||
* are source-level modifiers only, for which this method returns 0:
|
||||
* <ul>
|
||||
* <li>{@link #DEFAULT}: this doesn't exist at the class file level.
|
||||
* A default method is a non-static non-abstract public method declared
|
||||
* in an interface ({@link JMethodSymbol#isDefault()}).
|
||||
* <li>{@link #SEALED}: a sealed class has an attribute {@code PermittedSubclasses}
|
||||
* with a non-zero length (in the compiled class file)
|
||||
* <li>{@link #NON_SEALED}: this doesn't exist at the class file level at all.
|
||||
* But a class must have the non-sealed modifier in source if it
|
||||
* is neither sealed, nor final, and appears in the {@code PermittedSubclasses}
|
||||
* attribute of some direct supertype.
|
||||
* </ul>
|
||||
*/
|
||||
public int getReflectMod() {
|
||||
return reflect;
|
||||
|
@ -15,7 +15,6 @@ import net.sourceforge.pmd.internal.util.IteratorUtil;
|
||||
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.ASTAnyTypeDeclaration.TypeKind;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAssertStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCastExpression;
|
||||
@ -45,7 +44,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeTestPattern;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTYieldStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.AccessNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.JModifier;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVisitorBase;
|
||||
@ -478,9 +476,9 @@ public class LanguageLevelChecker<T> {
|
||||
|
||||
@Override
|
||||
public Void visit(ASTAnyTypeDeclaration node, T data) {
|
||||
if ((node.getModifiers() & (AccessNode.SEALED | AccessNode.NON_SEALED)) != 0) {
|
||||
if (node.getModifiers().hasAnyExplicitly(JModifier.SEALED, JModifier.NON_SEALED)) {
|
||||
check(node, PreviewFeature.SEALED_CLASSES, data);
|
||||
} else if (node.isLocal() && node.getTypeKind() != TypeKind.CLASS) {
|
||||
} else if (node.isLocal() && node.isInterface() || node.isEnum()) {
|
||||
check(node, PreviewFeature.SEALED_CLASSES, data);
|
||||
}
|
||||
|
||||
|
@ -173,6 +173,11 @@ public interface JClassSymbol extends JTypeDeclSymbol,
|
||||
|
||||
boolean isAnonymousClass();
|
||||
|
||||
// todo isSealed + getPermittedSubclasses
|
||||
// (isNonSealed is not so useful I think)
|
||||
|
||||
// todo getEnumConstants
|
||||
|
||||
/**
|
||||
* This returns true if this is not an interface, primitive or array.
|
||||
*/
|
||||
|
@ -12,6 +12,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType.*
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.*
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Earliest
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Latest
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.since
|
||||
import net.sourceforge.pmd.lang.java.ast.UnaryOp.UNARY_MINUS
|
||||
|
||||
/**
|
||||
@ -45,7 +46,7 @@ class ASTLiteralTest : ParserTestSpec({
|
||||
}
|
||||
}
|
||||
|
||||
parserTest("Text block literal", javaVersion = J13__PREVIEW) {
|
||||
parserTest("Text block literal", javaVersions = since(J14__PREVIEW)) {
|
||||
|
||||
val delim = "\"\"\""
|
||||
|
||||
@ -127,7 +128,7 @@ $delim
|
||||
}
|
||||
|
||||
|
||||
parserTest("Text block literal on non-JDK13 preview", javaVersions = JavaVersion.except(J13__PREVIEW, J14__PREVIEW)) {
|
||||
parserTest("Text block literal on non-JDK13 preview", javaVersions = Earliest.rangeTo(J14)) {
|
||||
|
||||
val delim = "\"\"\""
|
||||
|
||||
|
@ -18,7 +18,7 @@ import net.sourceforge.pmd.lang.java.ast.UnaryOp.UNARY_MINUS
|
||||
*/
|
||||
class ASTSwitchExpressionTests : ParserTestSpec({
|
||||
|
||||
val switchVersions = listOf(J13__PREVIEW, J14, J14__PREVIEW)
|
||||
val switchVersions = JavaVersion.since(J14)
|
||||
val notSwitchVersions = JavaVersion.except(switchVersions)
|
||||
|
||||
parserTest("No switch expr before j13 preview", javaVersions = notSwitchVersions) {
|
||||
|
@ -6,38 +6,32 @@ package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.test.shouldBe
|
||||
|
||||
class Java15KotlinTest: ParserTestSpec( {
|
||||
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::getEscapedStringLiteral shouldBe
|
||||
"\"\"\"\n" +
|
||||
" <html> \n" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p> \n" +
|
||||
" </body> \n" +
|
||||
" </html> \n" +
|
||||
" \"\"\""
|
||||
it::getTextBlockContent shouldBe
|
||||
"<html>\n" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p>\n" +
|
||||
" </body>\n" +
|
||||
"</html>\n"
|
||||
}
|
||||
}
|
||||
|
||||
val tblock = "\"\"\"\n" +
|
||||
// 4 spaces of insignificant indentation
|
||||
" <html> \n" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p> \n" +
|
||||
" </body> \n" +
|
||||
" </html> \n" +
|
||||
" \"\"\""
|
||||
|
||||
inContext(ExpressionParsingCtx) {
|
||||
tblock should parseAs {
|
||||
textBlock {
|
||||
it::getConstValue shouldBe "<html>\n" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p>\n" +
|
||||
" </body>\n" +
|
||||
"</html>\n"
|
||||
|
||||
it::getImage shouldBe tblock
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,8 @@ enum class JavaVersion : Comparable<JavaVersion> {
|
||||
val Latest = values().last()
|
||||
val Earliest = values().first()
|
||||
|
||||
fun since(v: JavaVersion) = v.rangeTo(Latest)
|
||||
|
||||
fun except(v1: JavaVersion, vararg versions: JavaVersion) =
|
||||
values().toList() - v1 - versions
|
||||
|
||||
|
Reference in New Issue
Block a user