Add generic visitor interface in pmd-core

Replace SideEffectingVisitor with JavaVisitor

The new visitor is generic. We don't actually need the
old Object->Object visitor, this could just be the new
generic visitor but erased

Port language level checker

Move delegators

Remove old accept methods

Remove reduced adapter

Cleanup some visitor

Make ant wrapper replace old visitor completely

Doc

Add DeprecatedUntil700 annotation

Add top interface for visitors

Convert JSP visitors

Checkstyle

Fix java module
This commit is contained in:
Clément Fournier
2020-04-28 08:38:10 +02:00
parent c3219b91c5
commit b88ddf41c0
186 changed files with 1109 additions and 1224 deletions

View File

@ -60,9 +60,9 @@
<property name="base-visitor-interface-name" value="${lang-name}ParserVisitor" />
<property name="base-visitor-interface-file" value="${target-package-dir}/${base-visitor-interface-name}.java" />
<property name="generic-sideeffect-visitor-interface-name" value="SideEffectingVisitor" />
<property name="generic-visitor-interface-name" value="${lang-name}Visitor" />
<property name="generic-sideeffect-visitor-interface-file"
value="${target-package-dir}/${generic-sideeffect-visitor-interface-name}.java" />
value="${target-package-dir}/${generic-visitor-interface-name}.java" />
<!-- TARGETS -->
@ -72,8 +72,8 @@
depends="checkUpToDate,init,jjtree,jjtree-ersatz,javacc,adapt-generated,default-visitor,cleanup" />
<target name="alljavacc-visitor+"
description="Like alljavacc, and adds another visitor"
depends="alljavacc,side-effecting-visitor" />
description="Like alljavacc, replaces default JJTree visitor with a generic one"
depends="alljavacc,generic-visitor-replacement" />
<target name="checkUpToDate"
description="Checks the input files are up to date">
@ -488,17 +488,16 @@ public interface" />
</target>
<target name="side-effecting-visitor" depends="default-visitor" unless="jjtreeBuildNotRequired">
<!-- Side effecting visitor, no return type, one generic parameter -->
<copy file="${base-visitor-interface-file}" tofile="${generic-sideeffect-visitor-interface-file}" />
<target name="generic-visitor-replacement" depends="default-visitor" unless="jjtreeBuildNotRequired">
<move file="${base-visitor-interface-file}" tofile="${generic-sideeffect-visitor-interface-file}" />
<replace file="${generic-sideeffect-visitor-interface-file}">
<replacefilter token="${base-visitor-interface-name}"
value="${generic-sideeffect-visitor-interface-name}&lt;T>" />
value="${generic-visitor-interface-name}&lt;P, R> extends ${ast-api-package}.AstVisitor&lt;P, R>" />
<replacefilter token="Object" value="T" />
<replacefilter token="T visit" value="void visit" />
<replacefilter token="return data;" value="" />
<replacefilter token="return " value="" />
<replacefilter token="Object" value="P" />
<replacefilter token="P visit" value="R visit" />
<replacefilter token="default R visit(${node-name} node, P data) { for (int i = 0, len = node.getNumChildren(); i &lt; len; i++) node.getChild(i).jjtAccept(this, data); return data; }" value="default R visit(${node-name} node, P data) { return visitNode(node, data); }" />
</replace>
</target>

View File

@ -0,0 +1,14 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.annotation;
/**
* Tags a deprecated member that should not be removed before PMD 7.0.0.
* Such members were made deprecated on the PMD 7 development branch and
* may be kept for backwards compatibility on the day of the PMD 7 release,
* because the replacement API cannot be backported to PMD 6.
*/
public @interface DeprecatedUntil700 {
}

View File

@ -0,0 +1,36 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast;
/**
* Root interface for AST visitors. Language modules publish a subinterface
* with one separate visit method for each type of node in the language,
* eg JavaVisitor.
*
* <p>Usually you never want to call {@code visit} methods manually, instead
* calling {@link Node#acceptVisitor(AstVisitor, Object) Node::acceptVisitor},
* which then dispatches to the most specific method of the visitor instance.
*
* <p>Use {@link Void} as a type parameter if you don't want a parameter type
* or a return type.
*
* @param <P> Parameter type of the visit method
* @param <R> Return type of the visit method
*/
public interface AstVisitor<P, R> {
/**
* Visit a node. This method is dispatched statically, you should
* use {@link Node#acceptVisitor(AstVisitor, Object)} if you want
* to call the most specific method instead.
*
* @param node Node to visit
* @param param Parameter
*
* @return Some result
*/
R visitNode(Node node, P param);
}

View File

@ -0,0 +1,57 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast;
/**
* Base implementation of {@link AstVisitor}, that performs a top-down
* (preorder) visit and may accumulate a result.
*/
public abstract class AstVisitorBase<P, R> implements AstVisitor<P, R> {
/** Initial value when combining values returned by children. */
protected R zero() {
return null;
}
/**
* Merge two values of type R, used to combine values returned by children.
*
* @param acc Current accumulated value for the previous siblings
* (or {@link #zero()} if the child is the first child)
* @param childValue Value for the new child
*
* @return New accumulated value to use for the next sibling
*/
protected R combine(R acc, R childValue) {
return acc;
}
/**
* Visit the children. By default the data parameter is passed unchanged
* to all descendants. The {@link #zero() zero} and {@link #combine(Object, Object) combine}
* functions should be implemented if this is to return something else
* than null.
*
* @param node Node whose children should be visited
* @param data Parameter of the visit
*
* @return Some value for the children
*/
// kept separate from super.visit for clarity
protected R visitChildren(Node node, P data) {
R result = zero();
for (Node child : node.children()) {
R r1 = child.acceptVisitor(this, data);
result = combine(result, r1);
}
return result;
}
@Override
public R visitNode(Node node, P param) {
return visitChildren(node, param);
}
}

View File

@ -280,6 +280,27 @@ public interface Node {
*/
int getIndexInParent();
/**
* Calls back the visitor's visit method corresponding to the runtime
* type of this Node. This should usually be preferred to calling
* a {@code visit} method directly (usually the only calls to those
* are in the implementations of this {@code acceptVisitor} method).
*
* @param visitor Visitor to dispatch
* @param param Parameter to the visit
* @param <R> Return type of the visitor
* @param <P> Parameter type of the visitor
*
* @return What the visitor returned
*/
// TODO remove the default implementation, convert all visitors to be generic
default <R, P> R acceptVisitor(AstVisitor<P, R> visitor, P param) {
// override me
return visitor.visitNode(this, param);
}
/**
* Gets the name of the node that is used to match it with XPath queries.
*

View File

@ -9,6 +9,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@ -580,6 +581,25 @@ public interface NodeStream<T extends Node> extends Iterable<@NonNull T> {
void forEach(Consumer<? super @NonNull T> action);
/**
* Reduce the elements of this stream sequentially.
*
* @param identity Identity element
* @param accumulate Combine an intermediate result with a new node from this stream,
* returns the next intermediate result
* @param <R> Result type
*
* @return The last intermediate result (identity if this stream is empty)
*/
default <R> R reduce(R identity, BiFunction<? super R, ? super T, ? extends R> accumulate) {
R result = identity;
for (T node : this) {
result = accumulate.apply(result, node);
}
return result;
}
/**
* Returns the number of nodes in this stream.
*

View File

@ -30,17 +30,10 @@ public class ASTAdditiveExpression extends AbstractJavaTypeNode {
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* @deprecated Use {@link #getOperator()}
*/

View File

@ -18,18 +18,13 @@ public class ASTAllocationExpression extends AbstractJavaTypeNode implements Jav
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* Returns true if this expression defines a body,
* which is compiled to an anonymous class. If this

View File

@ -29,14 +29,9 @@ public class ASTAndExpression extends AbstractJavaTypeNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
public <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -97,14 +97,9 @@ public class ASTAnnotation extends AbstractJavaTypeNode {
|| "java.lang.SuppressWarnings".equals(getAnnotationName());
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
public <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -14,18 +14,13 @@ public class ASTAnnotationMethodDeclaration extends AbstractMethodLikeNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
@Override
public MethodLikeKind getKind() {
return MethodLikeKind.METHOD;

View File

@ -15,13 +15,7 @@ public class ASTAnnotationTypeBody extends AbstractJavaNode {
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -16,18 +16,13 @@ public class ASTAnnotationTypeDeclaration extends AbstractAnyTypeDeclaration {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
@Override
public TypeKind getTypeKind() {
return TypeKind.ANNOTATION;

View File

@ -15,13 +15,7 @@ public class ASTAnnotationTypeMemberDeclaration extends AbstractTypeBodyDeclarat
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
public <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -15,15 +15,10 @@ public class ASTArgumentList extends AbstractJavaNode {
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* Gets the number of arguments.
*
@ -32,5 +27,4 @@ public class ASTArgumentList extends AbstractJavaNode {
public int size() {
return this.getNumChildren();
}
}

View File

@ -35,14 +35,9 @@ public class ASTArguments extends AbstractJavaNode {
return size();
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -16,18 +16,13 @@ public class ASTArrayDimsAndInits extends AbstractJavaNode implements Dimensiona
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
@Deprecated
public void bumpArrayDepth() {
arrayDepth++;

View File

@ -14,14 +14,9 @@ public class ASTArrayInitializer extends AbstractJavaNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -23,18 +23,13 @@ public class ASTAssertStatement extends AbstractJavaNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* Returns the expression tested by this assert statement.
*

View File

@ -36,14 +36,9 @@ public class ASTAssignmentOperator extends AbstractJavaNode {
return this.isCompound;
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -16,18 +16,13 @@ public class ASTBlock extends AbstractJavaNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
public <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
public boolean containsComment() {
return this.containsComment;
}

View File

@ -14,18 +14,13 @@ public class ASTBlockStatement extends AbstractJavaNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* Tells if this BlockStatement is an allocation statement. This is done by
*

View File

@ -26,14 +26,9 @@ public class ASTBooleanLiteral extends AbstractJavaTypeNode {
return this.isTrue;
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -14,17 +14,12 @@ public class ASTBreakStatement extends AbstractJavaNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
@Override
public String getImage() {
String result = super.getImage();

View File

@ -26,14 +26,9 @@ public class ASTCastExpression extends AbstractJavaTypeNode {
return intersectionTypes;
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
public <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
}

View File

@ -24,18 +24,12 @@ public class ASTCatchStatement extends AbstractJavaNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* Returns true if this node is a multi-catch statement,
* that is, it catches several unrelated exception types

View File

@ -24,18 +24,13 @@ public class ASTClassOrInterfaceBody extends AbstractJavaNode {
super(id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
public boolean isAnonymousInnerClass() {
return getParent() instanceof ASTAllocationExpression;
}

View File

@ -36,17 +36,11 @@ public class ASTClassOrInterfaceBodyDeclaration extends AbstractTypeBodyDeclarat
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
public boolean isAnonymousInnerClass() {
return getParent().getParent() instanceof ASTAllocationExpression;
}

View File

@ -38,7 +38,7 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration {
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@ -47,11 +47,6 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration {
return super.isPackagePrivate() && !isLocal();
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
public boolean isInterface() {
return this.isInterface;
}

View File

@ -23,17 +23,11 @@ public class ASTClassOrInterfaceType extends AbstractJavaTypeNode {
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
protected <P, R> R acceptVisitor(JavaVisitor<P, R> visitor, P data) {
return visitor.visit(this, data);
}
@Override
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
visitor.visit(this, data);
}
/**
* Checks whether the type this node is referring to is declared within the
* same compilation unit - either a class/interface or a enum type. You want

Some files were not shown because too many files have changed in this diff Show More