Fix #4912 - grammar for TWR allows this expression

This commit is contained in:
Clément Fournier
2024-04-05 10:19:58 +02:00
parent f2a586c6f2
commit 03b8d1acef
4 changed files with 19 additions and 17 deletions

View File

@ -2867,8 +2867,8 @@ void Resource() :
PrimaryExpression() PrimaryExpression()
{ {
Node top = jjtree.peekNode(); Node top = jjtree.peekNode();
if (!(top instanceof ASTVariableAccess || top instanceof ASTFieldAccess)) if (!(top instanceof ASTVariableAccess || top instanceof ASTFieldAccess || top instanceof ASTThisExpression))
throwParseException("Expected a variable access, but was a " + top.getXPathNodeName()); throwParseException("Expected a variable or field access, but was a " + top.getXPathNodeName());
} }
{} {}
} }

View File

@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.ast;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil;
/** /**
* A resource of a {@linkplain ASTTryStatement try-with-resources}. This contains another * A resource of a {@linkplain ASTTryStatement try-with-resources}. This contains another
@ -48,24 +49,16 @@ public final class ASTResource extends AbstractJavaNode {
* then returns the sequence of names that identifies the expression. * then returns the sequence of names that identifies the expression.
* If this has a local variable declaration, then returns the name * If this has a local variable declaration, then returns the name
* of the variable. * of the variable.
*
* <p>Note that this might be null if the expression is too complex.
*
* @deprecated Since 7.1.0. This method is not very useful because the expression
* might be complex and not have a real "name".
*/ */
@Deprecated
public String getStableName() { public String getStableName() {
if (isConciseResource()) { if (isConciseResource()) {
ASTExpression expr = getInitializer(); return PrettyPrintingUtil.prettyPrint(getInitializer()).toString();
StringBuilder builder = new StringBuilder();
while (expr instanceof ASTFieldAccess) {
ASTFieldAccess fa = (ASTFieldAccess) expr;
builder.insert(0, "." + fa.getName());
expr = fa.getQualifier();
}
// the last one may be ambiguous, or a variable reference
// the only common interface we have to get their name is
// unfortunately Node::getImage
if (expr != null) {
builder.insert(0, expr.getImage());
}
return builder.toString();
} else { } else {
return asLocalVariableDeclaration().iterator().next().getName(); return asLocalVariableDeclaration().iterator().next().getName();
} }

View File

@ -241,6 +241,7 @@ public final class PrettyPrintingUtil {
} }
/** Pretty print an expression or any other kind of node. */
public static CharSequence prettyPrint(JavaNode node) { public static CharSequence prettyPrint(JavaNode node) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
node.acceptVisitor(new ExprPrinter(), sb); node.acceptVisitor(new ExprPrinter(), sb);

View File

@ -132,8 +132,16 @@ class ASTTryStatementTest : ParserTestSpec({
} }
} }
// the expr must be a field access or var access
"try ( a.foo() ){}" shouldNot parse() "try ( a.foo() ){}" shouldNot parse()
"try (new Foo()){}" shouldNot parse() "try (new Foo()){}" shouldNot parse()
"try(arr[0]) {}" shouldNot parse()
"try ( a.foo().b ){}" should parse()
"try (new Foo().x){}" should parse()
// this is also allowed by javac
"try(this) {}" should parse()
"try(Foo.this) {}" should parse()
} }
} }