From 86b274c681f4d1edd3879f36ab259f889b7a5d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 17 Dec 2019 16:59:19 +0100 Subject: [PATCH] Make generic visitor superclass Use raw supertype to avoid conflicts --- .../lang/ast/xpath/AttributeAxisIterator.java | 2 +- .../java/ast/impl/BaseGenericVisitor.java | 75 +++++++++++++++++++ .../java/ast/JavaParserVisitorAdapter.java | 26 +++---- .../lang/jsp/ast/JspParserVisitorAdapter.java | 29 ++++--- .../modelica/ast/AbstractModelicaNode.java | 4 +- .../modelica/ast/AbstractModelicaRule.java | 4 +- .../pmd/lang/modelica/ast/ModelicaNode.java | 7 +- .../ast/ModelicaParserVisitorAdapter.java | 17 +++-- .../resolver/ScopeAndDeclarationFinder.java | 2 +- .../plsql/ast/PLSQLParserVisitorAdapter.java | 27 ++++--- .../scala/ast/ScalaParserVisitorAdapter.java | 22 ++---- .../pmd/lang/scala/rule/ScalaRule.java | 4 +- .../pmd/lang/vf/ast/AbstractVFNode.java | 2 +- .../sourceforge/pmd/lang/vf/ast/VfNode.java | 2 +- .../lang/vf/ast/VfParserVisitorAdapter.java | 20 ++++- .../lang/vm/ast/VmParserVisitorAdapter.java | 29 ++++--- 16 files changed, 177 insertions(+), 95 deletions(-) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/java/ast/impl/BaseGenericVisitor.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java index 8b03ac6dad..a1e5edeb2d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java @@ -40,7 +40,7 @@ public class AttributeAxisIterator implements Iterator { = new HashSet<>(Arrays.>asList(Integer.TYPE, Boolean.TYPE, Double.TYPE, String.class, Long.TYPE, Character.TYPE, Float.TYPE)); private static final Set FILTERED_OUT_NAMES - = new HashSet<>(Arrays.asList("toString","getNumChildren", "getIndexInParent", "getParent", "getClass", "getXPathNodeName", "getTypeNameNode", "hashCode", "getImportedNameNode", "getScope")); + = new HashSet<>(Arrays.asList("toString", "getNumChildren", "getIndexInParent", "getParent", "getClass", "getXPathNodeName", "getTypeNameNode", "hashCode", "getImportedNameNode", "getScope")); /* Iteration variables */ private Attribute currObj; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/java/ast/impl/BaseGenericVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/java/ast/impl/BaseGenericVisitor.java new file mode 100644 index 0000000000..79d1492f9b --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/java/ast/impl/BaseGenericVisitor.java @@ -0,0 +1,75 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast.impl; + +import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.lang.ast.Node; + +/** + * Base class for tree visitors that take one parameter, and return a + * value. + * + *

Non-generic subclasses extend only the raw type of this class. + * This is to avoid source-level incompatibilities when generifying + * those classes. For example, For now {@code JavaParserVisitor <: BaseGenericVisitor}, + * where the {@code AbstractVisitorAdapter} is a raw type. For 7.0.0, + * this relation will become {@code JavaParserVisitor <: BaseGenericVisitor}. + * Because {@code JavaParserVisitor} used to extend the raw type, the + * relation {@code JavaParserVisitor <: BaseGenericVisitor}, where + * now both are raw types, will still hold. On the other hand, if we today + * make {@code JavaParserVisitor} extend {@code BaseGenericVisitor}, + * then that relation will break in 7.0.0, as {@code JavaParserVisitor} + * as a raw type is not convertible to {@code BaseGenericVisitor} + * anymore, only to the other raw type {@code BaseGenericVisitor}. + * + * @param Type of node this visitor accepts + * @param

Type of parameter for the visitor + * @param Return type of the visit methods + */ +@Experimental +public abstract class BaseGenericVisitor { + + /** + * Initial value when combining values returned by children. + * Note that non-generic subclasses return {@code data} today, + * which is only valid if {@code R = P}. In 7.0.0 this will + * be changed to return null. + * + * @param parent Parent node + * @param data Value of the parameter for the parent + */ + protected R zero(N parent, P data) { + return null; + } + + /** + * Merge two values of type Object, used to combine values returned by children. + * By default returns the [newest] value. + * + * @param acc Accumulated value for the children preceding the current one + * @param newest Newest value to combine with the accumulator + * @param parent Parent node + * @param data Value of the parameter for the parent + * @param idx Index of the child in the parent, for which [newest] is the corresponding value + */ + protected R combine(R acc, R newest, N parent, P data, int idx) { + return newest; + } + + /** + * Make the node accept this visitor with parameter [data]. + */ + protected abstract R visitChildAt(N node, int idx, P data); + + + public R visit(N node, P data) { + R returnValue = zero(node, data); + for (int i = 0; i < node.getNumChildren(); ++i) { + returnValue = combine(returnValue, visitChildAt(node, i, data), node, data, i); + } + return returnValue; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java index b4784cacfe..14bd916e71 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java @@ -4,25 +4,25 @@ package net.sourceforge.pmd.lang.java.ast; -public class JavaParserVisitorAdapter implements JavaParserVisitor { +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.impl.BaseGenericVisitor; - /** Initial value when combining values returned by children. */ - protected Object zero() { - return null; - } +public class JavaParserVisitorAdapter extends BaseGenericVisitor implements JavaParserVisitor { - /** Merge two values of type Object, used to combine values returned by children. */ - protected Object combine(Object acc, Object r) { - return r; + @Override + protected Object zero(Node parent, Object data) { + return data; } @Override + protected Object visitChildAt(Node node, int idx, Object data) { + return ((JavaNode) node).getChild(idx).jjtAccept(this, data); + } + + @Override + @SuppressWarnings("unchecked") public Object visit(JavaNode node, Object data) { - Object returnValue = zero(); - for (int i = 0; i < node.getNumChildren(); ++i) { - returnValue = combine(returnValue, node.getChild(i).jjtAccept(this, data)); - } - return returnValue; + return super.visit(node, data); } @Override diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParserVisitorAdapter.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParserVisitorAdapter.java index df9dfabe76..21abfd9818 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParserVisitorAdapter.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParserVisitorAdapter.java @@ -4,26 +4,25 @@ package net.sourceforge.pmd.lang.jsp.ast; -public class JspParserVisitorAdapter implements JspParserVisitor { +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.impl.BaseGenericVisitor; +public class JspParserVisitorAdapter extends BaseGenericVisitor implements JspParserVisitor { - /** Initial value when combining values returned by children. */ - protected Object zero() { - return null; - } - - /** Merge two values of type R, used to combine values returned by children. */ - protected Object combine(Object acc, Object r) { - return r; + @Override + protected Object zero(Node parent, Object data) { + return data; } @Override - public Object visit(final JspNode node, final Object data) { - Object returnValue = zero(); - for (int i = 0; i < node.getNumChildren(); ++i) { - returnValue = combine(returnValue, node.getChild(i).jjtAccept(this, data)); - } - return returnValue; + protected Object visitChildAt(Node node, int idx, Object data) { + return ((JspNode) node).getChild(idx).jjtAccept(this, data); + } + + @Override + @SuppressWarnings("unchecked") + public Object visit(JspNode node, Object data) { + return super.visit(node, data); } @Override diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaNode.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaNode.java index 08e050d612..814a73ba38 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaNode.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaNode.java @@ -4,8 +4,8 @@ package net.sourceforge.pmd.lang.modelica.ast; -import net.sourceforge.pmd.lang.ast.AbstractNode; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.impl.javacc.AbstractJjtreeNode; import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope; /** @@ -17,7 +17,7 @@ import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope; * * @see ModelicaNode for public API. */ -abstract class AbstractModelicaNode extends AbstractNode implements Node, ModelicaNode { +abstract class AbstractModelicaNode extends AbstractJjtreeNode implements Node, ModelicaNode { private ModelicaParser parser; private ModelicaScope ownScope; diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaRule.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaRule.java index b0c00acf6b..60dea303e3 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaRule.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/AbstractModelicaRule.java @@ -35,8 +35,8 @@ public abstract class AbstractModelicaRule extends AbstractRule implements Model @Override public Object visit(AbstractModelicaNode node, Object data) { - for (int i = 0; i < node.jjtGetNumChildren(); ++i) { - node.jjtGetChild(i).jjtAccept(this, data); + for (int i = 0; i < node.getNumChildren(); ++i) { + node.getChild(i).jjtAccept(this, data); } return data; } diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaNode.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaNode.java index 54bb3fc2e4..fccdff6502 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaNode.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaNode.java @@ -19,15 +19,16 @@ public interface ModelicaNode extends Node { /** * Returns the most specific lexical scope naturally associated with this node. * - * @return the scope defined by this node itself or the same as {@link getContainingScope} otherwise + * @return the scope defined by this node itself or the same as {@link #getContainingScope()} otherwise */ ModelicaScope getMostSpecificScope(); Object jjtAccept(ModelicaParserVisitor visitor, Object data); @Override - ModelicaNode jjtGetParent(); + ModelicaNode getParent(); + @Override - ModelicaNode jjtGetChild(int index); + ModelicaNode getChild(int index); } diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParserVisitorAdapter.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParserVisitorAdapter.java index 8ff1b60385..e0ddccc045 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParserVisitorAdapter.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParserVisitorAdapter.java @@ -4,12 +4,19 @@ package net.sourceforge.pmd.lang.modelica.ast; -public class ModelicaParserVisitorAdapter implements ModelicaParserVisitor { +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.impl.BaseGenericVisitor; + +public class ModelicaParserVisitorAdapter extends BaseGenericVisitor implements ModelicaParserVisitor { + + @Override + protected Object visitChildAt(Node node, int idx, Object data) { + return ((ModelicaNode) node).getChild(idx).jjtAccept(this, data); + } + + @SuppressWarnings("unchecked") public Object visit(ModelicaNode node, Object data) { - for (int i = 0; i < node.jjtGetNumChildren(); ++i) { - node.jjtGetChild(i).jjtAccept(this, data); - } - return data; + return super.visit(node, data); } @Override diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/resolver/ScopeAndDeclarationFinder.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/resolver/ScopeAndDeclarationFinder.java index 58223e9ccc..d1d7dc21bc 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/resolver/ScopeAndDeclarationFinder.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/resolver/ScopeAndDeclarationFinder.java @@ -29,7 +29,7 @@ public class ScopeAndDeclarationFinder extends ModelicaParserVisitorAdapter { } private void createClassDeclaration(ASTClassDefinition node) { - ModelicaScope containingScope = ((ModelicaNode) node.jjtGetParent()).getMostSpecificScope(); + ModelicaScope containingScope = node.getParent().getMostSpecificScope(); ModelicaClassDeclaration declaration = new ModelicaClassDeclaration(node); ((AbstractModelicaScope) containingScope).addDeclaration(declaration); diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java index 931e43492d..5e5f579413 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java @@ -4,26 +4,25 @@ package net.sourceforge.pmd.lang.plsql.ast; -public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.impl.BaseGenericVisitor; +public class PLSQLParserVisitorAdapter extends BaseGenericVisitor implements PLSQLParserVisitor { - /** Initial value when combining values returned by children. */ - protected Object zero() { - return null; - } - - /** Merge two values of type R, used to combine values returned by children. */ - protected Object combine(Object acc, Object r) { - return r; + @Override + protected Object zero(Node parent, Object data) { + return data; } @Override + protected Object visitChildAt(Node node, int idx, Object data) { + return ((PLSQLNode) node).getChild(idx).jjtAccept(this, data); + } + + @Override + @SuppressWarnings("unchecked") public Object visit(PLSQLNode node, Object data) { - Object returnValue = zero(); - for (int i = 0; i < node.getNumChildren(); ++i) { - returnValue = combine(returnValue, node.getChild(i).jjtAccept(this, data)); - } - return returnValue; + return super.visit(node, data); } @Override diff --git a/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParserVisitorAdapter.java b/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParserVisitorAdapter.java index 2ca6a8fca6..9bf9b55996 100644 --- a/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParserVisitorAdapter.java +++ b/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParserVisitorAdapter.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.scala.ast; +import net.sourceforge.pmd.lang.java.ast.impl.BaseGenericVisitor; + import scala.meta.Case; import scala.meta.Ctor; import scala.meta.Decl; @@ -33,25 +35,11 @@ import scala.meta.Type; * @param * The type of the returned data */ -public class ScalaParserVisitorAdapter implements ScalaParserVisitor { - - /** 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. */ - protected R combine(R acc, R r) { - return r; - } +public class ScalaParserVisitorAdapter extends BaseGenericVisitor, R, D> implements ScalaParserVisitor { @Override - public R visit(ScalaNode node, D data) { - R returnValue = zero(); - for (int i = 0; i < node.getNumChildren(); ++i) { - returnValue = combine(returnValue, node.getChild(i).accept(this, data)); - } - return returnValue; + protected R visitChildAt(ScalaNode node, int idx, D data) { + return node.getChild(idx).accept(this, data); } @Override diff --git a/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/rule/ScalaRule.java b/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/rule/ScalaRule.java index f625ff3940..efc31631a6 100644 --- a/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/rule/ScalaRule.java +++ b/pmd-scala/src/main/java/net/sourceforge/pmd/lang/scala/rule/ScalaRule.java @@ -186,8 +186,8 @@ public class ScalaRule extends AbstractRule implements ScalaParserVisitor node, RuleContext data) { - for (int i = 0; i < node.jjtGetNumChildren(); ++i) { - node.jjtGetChild(i).accept(this, data); + for (int i = 0; i < node.getNumChildren(); ++i) { + node.getChild(i).accept(this, data); } return data; } diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java index 1b8ed642b3..ce56d7ea74 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.vf.ast; import net.sourceforge.pmd.lang.java.ast.impl.javacc.AbstractJjtreeNode; -public class AbstractVFNode extends AbstractJjtreeNode implements VfNode { +public class AbstractVFNode extends AbstractJjtreeNode implements VfNode { protected VfParser parser; diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfNode.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfNode.java index e8ae5ce81f..bbcaaaa961 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfNode.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfNode.java @@ -30,5 +30,5 @@ public interface VfNode extends Node, TokenBasedNode { @Override - VfNode jjtGetChild(int i); + VfNode getChild(int i); } diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParserVisitorAdapter.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParserVisitorAdapter.java index 693bda0b51..48599d53e6 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParserVisitorAdapter.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParserVisitorAdapter.java @@ -4,14 +4,28 @@ package net.sourceforge.pmd.lang.vf.ast; -public class VfParserVisitorAdapter implements VfParserVisitor { +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.impl.BaseGenericVisitor; + +public class VfParserVisitorAdapter extends BaseGenericVisitor implements VfParserVisitor { @Override - public Object visit(VfNode node, Object data) { - node.childrenAccept(this, data); + protected Object zero(Node parent, Object data) { return data; } + @Override + protected Object visitChildAt(Node node, int idx, Object data) { + return ((VfNode) node).getChild(idx).jjtAccept(this, data); + } + + @Override + @SuppressWarnings("unchecked") + public Object visit(VfNode node, Object data) { + return super.visit(node, data); + } + + @Override public Object visit(ASTCompilationUnit node, Object data) { return visit((VfNode) node, data); diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParserVisitorAdapter.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParserVisitorAdapter.java index 351f87e313..b2a4422fe4 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParserVisitorAdapter.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParserVisitorAdapter.java @@ -1,26 +1,25 @@ package net.sourceforge.pmd.lang.vm.ast; -public class VmParserVisitorAdapter implements VmParserVisitor { +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.impl.BaseGenericVisitor; +public class VmParserVisitorAdapter extends BaseGenericVisitor implements VmParserVisitor { - /** Initial value when combining values returned by children. */ - protected Object zero() { - return null; - } - - /** Merge two values of type R, used to combine values returned by children. */ - protected Object combine(Object acc, Object r) { - return r; + @Override + protected Object zero(Node parent, Object data) { + return data; } @Override - public Object visit(final VmNode node, final Object data) { - Object returnValue = zero(); - for (int i = 0; i < node.getNumChildren(); ++i) { - returnValue = combine(returnValue, node.getChild(i).jjtAccept(this, data)); - } - return returnValue; + protected Object visitChildAt(Node node, int idx, Object data) { + return ((VmNode) node).getChild(idx).jjtAccept(this, data); + } + + @Override + @SuppressWarnings("unchecked") + public Object visit(VmNode node, Object data) { + return super.visit(node, data); } @Override