Separate catch formal from method formal

This commit is contained in:
Clément Fournier
2019-07-20 13:08:49 +02:00
parent d4da257dc6
commit db1344d5aa
8 changed files with 227 additions and 12 deletions

View File

@ -2980,10 +2980,28 @@ void CatchClause() :
{}
{
"catch"
"(" FormalParameter() ")"
"(" CatchParameter() ")"
Block()
}
void CatchParameter() :
{boolean isFinal = false;}
{
isFinal=LocalVarModifierList() UnionType() VariableDeclaratorId()
}
// Special type for catch formal parameters
// Eg `IOException | ParseException`
void UnionType() #UnionType(isUnion):
{boolean isUnion=false;}
{
// Annotations of the first class type belong to the
// catch parameter (the variable) because of syntactic ambiguity
// This is similar to how a local var type works.
ClassOrInterfaceType() ( "|" {isUnion=true; checkForBadMultipleExceptionsCatching();} AnnotatedClassOrInterfaceType() )*
}
void FinallyClause() :
{}
{

View File

@ -49,15 +49,28 @@ public final class ASTCatchClause extends AbstractJavaNode {
* @return True if this node is a multi-catch statement
*/
public boolean isMulticatchStatement() {
return getCaughtExceptionTypeNodes().size() > 1; // the list is parsed multiple times...
return getFormal().isMultiCatch();
}
/**
* Returns the {@linkplain ASTCatchParameter CatchParameter} node.
*/
public ASTCatchParameter getFormal() {
return (ASTCatchParameter) jjtGetChild(0);
}
/**
* Returns the ID of the declared variable.
*/
public ASTVariableDeclaratorId getVariableId() {
return getFormal().getVariableId();
}
/**
* Returns the Block node of this catch branch.
*/
public ASTBlock getBlock() {
return getFirstChildOfType(ASTBlock.class);
return (ASTBlock) getLastChild();
}
/**
@ -67,7 +80,7 @@ public final class ASTCatchClause extends AbstractJavaNode {
*/
public List<ASTType> getCaughtExceptionTypeNodes() {
// maybe cache the list
return getFirstChildOfType(ASTFormalParameter.class).findChildrenOfType(ASTType.class);
return getFormal().getTypeNode().asList();
}
@ -89,7 +102,7 @@ public final class ASTCatchClause extends AbstractJavaNode {
* Returns exception name caught by this catch block.
*/
public String getExceptionName() {
return getFirstDescendantOfType(ASTVariableDeclaratorId.class).getImage();
return getVariableId().getVariableName();
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.InternalApi;
/**
* Formal parameter of a {@linkplain ASTCatchStatement catch statement}.
* The type node may be a {@link ASTUnionType union type}, which represents
* multi-catch clauses.
*
* TODO warning suppression
*
* <pre class="grammar">
*
* CatchParameter ::= ( "final" | {@link ASTAnnotation Annotation} )* {@link ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
*
* </pre>
*/
public class ASTCatchParameter extends AbstractJavaTypeNode implements Annotatable {
private boolean isFinal;
@InternalApi
@Deprecated
public ASTCatchParameter(int id) {
super(id);
}
ASTCatchParameter(JavaParser p, int id) {
super(p, id);
}
public boolean isFinal() {
return isFinal;
}
void setFinal(boolean f) {
isFinal = f;
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* Returns the declarator ID of this catch parameter.
*/
public ASTVariableDeclaratorId getVariableId() {
return (ASTVariableDeclaratorId) getLastChild();
}
/**
* Returns the type node of this formal parameter. This may be
* a {@linkplain ASTUnionType union type}.
*/
public ASTType getTypeNode() {
return getFirstChildOfType(ASTType.class);
}
/**
* Returns true if this is a multi-catch node.
*/
public boolean isMultiCatch() {
return getTypeNode() instanceof ASTUnionType;
}
}

View File

@ -5,6 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.Iterator;
import java.util.List;
/**
@ -24,7 +25,7 @@ import java.util.Iterator;
*
* </pre>
*/
public final class ASTIntersectionType extends AbstractJavaTypeNode implements ASTReferenceType, Iterable<ASTType> {
public final class ASTIntersectionType extends AbstractJavaTypeNode implements ASTReferenceType, JSingleChildNode<ASTType>, Iterable<ASTType> {
ASTIntersectionType(int id) {
super(id);
@ -43,6 +44,18 @@ public final class ASTIntersectionType extends AbstractJavaTypeNode implements A
}
@Override
public List<ASTType> asList() {
return findChildrenOfType(ASTType.class);
}
@Override
public ASTType jjtGetChild(int index) {
return (ASTType) super.jjtGetChild(index);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
return visitor.visit(this, data);

View File

@ -5,6 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.Iterator;
import java.util.List;
/**
* A list of resources in a {@linkplain ASTTryStatement try-with-resources}.
@ -15,7 +16,7 @@ import java.util.Iterator;
*
* </pre>
*/
public final class ASTResourceList extends AbstractJavaNode implements Iterable<ASTResource> {
public final class ASTResourceList extends AbstractJavaNode implements Iterable<ASTResource>, JSingleChildNode<ASTResource> {
private boolean trailingSemi;
@ -38,6 +39,11 @@ public final class ASTResourceList extends AbstractJavaNode implements Iterable<
visitor.visit(this, data);
}
@Override
public ASTResource jjtGetChild(int index) {
return (ASTResource) super.jjtGetChild(index);
}
void setTrailingSemi() {
this.trailingSemi = true;
}
@ -54,4 +60,9 @@ public final class ASTResourceList extends AbstractJavaNode implements Iterable<
public Iterator<ASTResource> iterator() {
return children(ASTResource.class).iterator();
}
public List<ASTResource> asList() {
return findChildrenOfType(ASTResource.class);
}
}

View File

@ -9,8 +9,6 @@ import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.internal.util.IteratorUtil;
/**
* Try statement node.
@ -57,13 +55,13 @@ public final class ASTTryStatement extends AbstractStatement {
}
@Nullable
public ASTResourceList getResourceList() {
public ASTResourceList getResourceListNode() {
return AstImplUtil.getChildAs(this, 0, ASTResourceList.class);
}
public List<ASTResource> getResources() {
ASTResourceList list = getResourceList();
return list == null ? Collections.emptyList() : IteratorUtil.toList(list.iterator());
ASTResourceList list = getResourceListNode();
return list == null ? Collections.emptyList() : list.asList();
}
@ -88,6 +86,7 @@ public final class ASTTryStatement extends AbstractStatement {
*
* @return The finally statement, or null if there is none
*/
@Nullable
public ASTFinallyClause getFinallyClause() {
return getFirstChildOfType(ASTFinallyClause.class);
}

View File

@ -4,6 +4,9 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.annotation.Experimental;
@ -71,6 +74,17 @@ public interface ASTType extends TypeNode, Annotatable {
}
/**
* Returns a read-only list of the components of this type.
* Returns a singleton containing this type if this is neither
* a {@linkplain ASTUnionType union type} or a {@linkplain ASTIntersectionType intersection type}.
* In those cases, returns the list of components.
*/
default List<ASTType> asList() {
return Collections.singletonList(this);
}
default boolean isClassOrInterfaceType() {
return this instanceof ASTClassOrInterfaceType;
}

View File

@ -0,0 +1,67 @@
/*
* 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 java.util.List;
/**
* Represents the type node of a multi-catch statement. This node is used
* to make the grammar of {@link ASTCatchStatement CatchStatement} more
* straightforward. Note though, that the Java type system does not feature
* union types per se. The type of this node is defined as the least upper-bound
* of all its components.
*
* <pre class="grammar">
*
* UnionType ::= {@link ASTClassOrInterfaceType ClassType} ("|" {@link ASTClassOrInterfaceType ClassType})+
*
* </pre>
*/
public final class ASTUnionType extends AbstractJavaTypeNode implements ASTReferenceType, JSingleChildNode<ASTClassOrInterfaceType>, Iterable<ASTClassOrInterfaceType> {
ASTUnionType(int id) {
super(id);
}
ASTUnionType(JavaParser p, int id) {
super(p, id);
}
@Override
public String getTypeImage() {
// TODO
return iterator().next().getTypeImage();
}
@Override
public List<ASTType> asList() {
return findChildrenOfType(ASTType.class);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
@Override
public Iterator<ASTClassOrInterfaceType> iterator() {
return new NodeChildrenIterator<>(this, ASTClassOrInterfaceType.class);
}
@Override
public ASTClassOrInterfaceType jjtGetChild(int index) {
return (ASTClassOrInterfaceType) super.jjtGetChild(index);
}
}