Fix merge wip

This commit is contained in:
Clément Fournier
2020-08-22 21:39:14 +02:00
parent 8fd4cf274e
commit 9eb6602b7c
11 changed files with 79 additions and 85 deletions

View File

@ -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()
}
/*

View File

@ -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());
}
}

View File

@ -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) {

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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.
*/

View File

@ -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 = "\"\"\""

View File

@ -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) {

View File

@ -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
}
}
}
}

View File

@ -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