forked from phoedos/pmd
Transform antlr visitor to be compatible with #2589
This commit is contained in:
@ -15,29 +15,103 @@
|
||||
|
||||
<property name="target-package-dir" value="${antlr4.outputDirectory}/net/sourceforge/pmd/lang/${lang-terse-name}/ast"/>
|
||||
|
||||
|
||||
<property name="lang-ast-package" value="net.sourceforge.pmd.lang.${lang-terse-name}.ast" />
|
||||
<property name="ast-api-package" value="net.sourceforge.pmd.lang.ast" />
|
||||
<property name="ast-impl-package" value="${ast-api-package}.impl.antlr4" />
|
||||
|
||||
|
||||
<property name="parser-name" value="${lang-name}Parser"/>
|
||||
<property name="parser-file" value="${target-package-dir}/${parser-name}.java"/>
|
||||
|
||||
<property name="visitor-name" value="${lang-name}Visitor"/>
|
||||
<property name="visitor-file" value="${target-package-dir}/${visitor-name}.java"/>
|
||||
|
||||
<property name="base-visitor-name" value="${lang-name}BaseVisitor"/>
|
||||
<property name="base-visitor-file" value="${target-package-dir}/${base-visitor-name}.java"/>
|
||||
|
||||
<property name="node-itf-name" value="${lang-name}Node"/>
|
||||
<property name="base-class-name" value="Abstract${lang-name}Node"/>
|
||||
|
||||
<target name="adapt-antlr-sources" description="Adapt antlr sources to the PMD codebase">
|
||||
|
||||
<replace file="${target-package-dir}/${lang-name}Parser.java"
|
||||
token="${root-node-name}Context extends ${lang-name}InnerNode"
|
||||
value="${root-node-name}Context extends ${lang-name}InnerNode implements net.sourceforge.pmd.lang.ast.RootNode"/>
|
||||
<!-- Adapt parser. -->
|
||||
<replace file="${parser-file}">
|
||||
<replacefilter token="${root-node-name}Context extends ${lang-name}InnerNode"
|
||||
value="${root-node-name}Context extends ${lang-name}InnerNode implements net.sourceforge.pmd.lang.ast.RootNode"/>
|
||||
|
||||
<replace file="${target-package-dir}/${lang-name}Parser.java"
|
||||
token="_ctx = _localctx;"
|
||||
value="_ctx = _localctx.asAntlrNode();"/>
|
||||
<replacefilter token="_ctx = _localctx;"
|
||||
value="_ctx = _localctx.asAntlrNode();"/>
|
||||
|
||||
<replace file="${target-package-dir}/${lang-name}Parser.java"
|
||||
token="else return visitor.visitChildren(this);"
|
||||
value="
|
||||
else if (visitor instanceof PmdAntlrVisitor) return ((PmdAntlrVisitor<? extends T>) visitor).visitChildren(this);
|
||||
else return visitor.visitChildren(asAntlrNode());"/>
|
||||
<replacefilter token="public <T> T accept(ParseTreeVisitor<? extends T> visitor)"
|
||||
value="public <P, R> R acceptVisitor(AstVisitor<? super P, ? extends R> visitor, P data)" />
|
||||
|
||||
<replaceregexp flags="g" file="${target-package-dir}/${lang-name}Parser.java">
|
||||
<replacefilter token="((${visitor-name}<? extends T>)visitor)"
|
||||
value="((${visitor-name}<? super P, ? extends R>) visitor)" />
|
||||
|
||||
<replacefilter token="return visitor.visitChildren(this);"
|
||||
value="return visitor.visitNode(this, data);" />
|
||||
|
||||
</replace>
|
||||
|
||||
<replaceregexp flags="g" file="${parser-file}">
|
||||
<regexp pattern="\.visit(\w++)\(this\);"/>
|
||||
<substitution expression=".visit\1(this, data);"/>
|
||||
</replaceregexp>
|
||||
|
||||
<replaceregexp flags="g" file="${parser-file}">
|
||||
<regexp pattern="_sempred\(\((\w+)\)_localctx,"/>
|
||||
<substitution expression="_sempred\((\1) asPmdNode(_localctx),"/>
|
||||
</replaceregexp>
|
||||
|
||||
<replace file="${target-package-dir}/${lang-name}Visitor.java"
|
||||
token="extends ParseTreeVisitor"
|
||||
value="extends net.sourceforge.pmd.lang.ast.impl.antlr4.PmdAntlrVisitor"/>
|
||||
<!-- Transform the visitor to PMD-style. -->
|
||||
<replace file="${visitor-file}">
|
||||
|
||||
<replacefilter token="Visitor<T> extends ParseTreeVisitor<T> {"
|
||||
value="Visitor<P, R> extends net.sourceforge.pmd.lang.ast.AstVisitor<P, R> {
|
||||
|
||||
/**
|
||||
* The default visit method for ${lang-name} nodes. Unless overridden,
|
||||
* the default implementations of the methods of this interface delegate
|
||||
* to this method. The default calls {@link #visitNode(Node, Object)}.
|
||||
*
|
||||
* @param node Node to visit
|
||||
* @param data Parameter of the visit
|
||||
* @return Result of the visit
|
||||
*/
|
||||
default R visit${node-itf-name}(${node-itf-name} node, P data) { return visitNode(node, data); }
|
||||
|
||||
"/>
|
||||
|
||||
<replacefilter token="T visit" value="default R visit"/>
|
||||
<replacefilter token="ctx);" value="node, P data) { return visit${node-itf-name}(node, data); }"/>
|
||||
|
||||
</replace>
|
||||
|
||||
<replace file="${visitor-file}">
|
||||
|
||||
<replacefilter token="Visitor<T> extends ParseTreeVisitor<T> {"
|
||||
value="Visitor<P, R> extends net.sourceforge.pmd.lang.ast.AstVisitor<P, R> {
|
||||
|
||||
/**
|
||||
* The default visit method for ${lang-name} nodes. Unless overridden,
|
||||
* the default implementations of the methods of this interface delegate
|
||||
* to this method. The default calls {@link #visitNode(Node, Object)}.
|
||||
*
|
||||
* @param node Node to visit
|
||||
* @param data Parameter of the visit
|
||||
* @return Result of the visit
|
||||
*/
|
||||
default R visit${node-itf-name}(${node-itf-name} node, P data) { return visitNode(node, data); }
|
||||
|
||||
"/>
|
||||
|
||||
<replacefilter token="T visit" value="default R visit"/>
|
||||
<replacefilter token="ctx);" value="node, P data) { return visit${node-itf-name}(node, data); }"/>
|
||||
|
||||
</replace>
|
||||
|
||||
<!-- This is in the main sources (not much to do). -->
|
||||
<delete file="${base-visitor-file}" />
|
||||
</target>
|
||||
</project>
|
||||
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.ast;
|
||||
|
||||
// The AstVisitor of #2589
|
||||
public interface AstVisitor<P, R> {
|
||||
|
||||
R visitNode(Node node, P param);
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.ast;
|
||||
|
||||
// The AstVisitorBase of #2589 (simplified, keep the other instead)
|
||||
public abstract class AstVisitorBase<P, R> implements AstVisitor<P, R> {
|
||||
|
||||
protected R visitChildren(Node node, P data) {
|
||||
for (Node child : node.children()) {
|
||||
child.acceptVisitor(this, data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visitNode(Node node, P param) {
|
||||
return visitChildren(node, param);
|
||||
}
|
||||
|
||||
}
|
@ -244,6 +244,7 @@ public interface Node {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a data map used to store additional information on this node.
|
||||
*
|
||||
@ -251,6 +252,13 @@ public interface Node {
|
||||
*/
|
||||
DataMap<DataKey<?, ?>> getUserMap();
|
||||
|
||||
|
||||
// The acceptVisitor of #2589
|
||||
default <P, R> R acceptVisitor(AstVisitor<? super P, ? extends R> visitor, P data) {
|
||||
return visitor.visitNode(this, data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parent of this node, or null if this is the {@linkplain RootNode root}
|
||||
* of the tree.
|
||||
@ -259,6 +267,7 @@ public interface Node {
|
||||
*/
|
||||
Node getParent();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the child of this node at the given index.
|
||||
*
|
||||
|
@ -6,9 +6,8 @@ package net.sourceforge.pmd.lang.ast.impl.antlr4;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.ast.AstVisitor;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRule;
|
||||
|
||||
@ -23,13 +22,11 @@ public abstract class AntlrBaseRule extends AbstractRule {
|
||||
|
||||
@Override
|
||||
public void apply(List<? extends Node> nodes, RuleContext ctx) {
|
||||
ParseTreeVisitor<Void> visitor = buildVisitor(ctx);
|
||||
AstVisitor<RuleContext, ?> visitor = buildVisitor();
|
||||
assert visitor != null : "Rule should provide a non-null visitor";
|
||||
|
||||
for (Node node : nodes) {
|
||||
assert node instanceof BaseAntlrNode : "Incorrect node type " + node + " passed to " + this;
|
||||
|
||||
((BaseAntlrNode<?, ?>) node).accept(visitor);
|
||||
node.acceptVisitor(visitor, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,10 +35,8 @@ public abstract class AntlrBaseRule extends AbstractRule {
|
||||
* This visitor should explore the nodes it's interested in and report
|
||||
* violations on the given rule context.
|
||||
*
|
||||
* @param ruleCtx Object that accumulates rule violations
|
||||
*
|
||||
* @return A visitor bound to the given rule context
|
||||
*/
|
||||
public abstract ParseTreeVisitor<Void> buildVisitor(RuleContext ruleCtx);
|
||||
public abstract AstVisitor<RuleContext, ?> buildVisitor();
|
||||
|
||||
}
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.ast.impl.antlr4;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
|
||||
|
||||
/**
|
||||
@ -13,6 +11,4 @@ import net.sourceforge.pmd.lang.ast.impl.GenericNode;
|
||||
*/
|
||||
public interface AntlrNode<N extends AntlrNode<N>> extends GenericNode<N> {
|
||||
|
||||
<T> T accept(ParseTreeVisitor<? extends T> visitor);
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
package net.sourceforge.pmd.lang.ast.impl.antlr4;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public abstract class BaseAntlrErrorNode<N extends AntlrNode<N>> extends BaseAntlrTerminalNode<N> {
|
||||
@ -20,12 +19,6 @@ public abstract class BaseAntlrErrorNode<N extends AntlrNode<N>> extends BaseAnt
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
|
||||
return visitor.visitErrorNode(asAntlrNode());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NonNull String getText() {
|
||||
return getFirstAntlrToken().getText();
|
||||
|
@ -102,12 +102,6 @@ public abstract class BaseAntlrInnerNode<N extends AntlrNode<N>> extends BaseAnt
|
||||
// default does nothing
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
|
||||
return visitor.visitChildren(asAntlrNode());
|
||||
}
|
||||
|
||||
protected static class PmdAsAntlrInnerNode<N extends AntlrNode<N>> extends ParserRuleContext implements RuleNode, AntlrToPmdParseTreeAdapter<N> {
|
||||
|
||||
private final BaseAntlrInnerNode<N> pmdNode;
|
||||
@ -154,9 +148,7 @@ public abstract class BaseAntlrInnerNode<N extends AntlrNode<N>> extends BaseAnt
|
||||
|
||||
@Override
|
||||
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
|
||||
// note: this delegate to the PMD node, giving
|
||||
// control of the visit back to the first-class nodes
|
||||
return pmdNode.accept(visitor);
|
||||
throw new UnsupportedOperationException("Cannot visit the underlying antlr nodes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,11 +62,6 @@ public abstract class BaseAntlrTerminalNode<N extends AntlrNode<N>>
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
|
||||
return visitor.visitTerminal(asAntlrNode());
|
||||
}
|
||||
|
||||
protected int getTokenKind() {
|
||||
return antlrNode.symbol.getTokenIndex();
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.ast.impl.antlr4;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
import org.antlr.v4.runtime.tree.RuleNode;
|
||||
|
||||
/**
|
||||
* Interface for parse tree visitors that can also visit PMD nodes. The
|
||||
* antlr rewrite makes the generated visitor interface extend this.
|
||||
*/
|
||||
public interface PmdAntlrVisitor<T> extends ParseTreeVisitor<T> {
|
||||
|
||||
@Override
|
||||
T visitChildren(RuleNode node);
|
||||
|
||||
|
||||
/**
|
||||
* This is added for compatibility.
|
||||
*/
|
||||
default T visitChildren(BaseAntlrInnerNode<?> node) {
|
||||
return visitChildren(node.asAntlrNode());
|
||||
}
|
||||
|
||||
}
|
@ -35,6 +35,7 @@ grammar Swift;
|
||||
|
||||
@header {
|
||||
import net.sourceforge.pmd.lang.ast.impl.antlr4.*;
|
||||
import net.sourceforge.pmd.lang.ast.AstVisitor;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,9 +4,8 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.swift;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.ast.AstVisitor;
|
||||
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrBaseRule;
|
||||
|
||||
public abstract class AbstractSwiftRule extends AntlrBaseRule {
|
||||
@ -16,5 +15,5 @@ public abstract class AbstractSwiftRule extends AntlrBaseRule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract ParseTreeVisitor<Void> buildVisitor(RuleContext ruleCtx);
|
||||
public abstract AstVisitor<RuleContext, ?> buildVisitor();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.swift.ast;
|
||||
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.AstVisitor;
|
||||
import net.sourceforge.pmd.lang.ast.impl.antlr4.BaseAntlrInnerNode;
|
||||
|
||||
public abstract class SwiftInnerNode
|
||||
@ -19,6 +20,16 @@ public abstract class SwiftInnerNode
|
||||
super(parent, invokingStateNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P, R> R acceptVisitor(AstVisitor<? super P, ? extends R> visitor, P data) {
|
||||
if (visitor instanceof SwiftVisitor) {
|
||||
// some of the generated antlr nodes have no accept method...
|
||||
return ((SwiftVisitor<? super P, ? extends R>) visitor).visitSwiftNode(this, data);
|
||||
}
|
||||
return visitor.visitNode(this, data);
|
||||
}
|
||||
|
||||
|
||||
@Override // override to make visible in package
|
||||
protected PmdAsAntlrInnerNode<SwiftNode> asAntlrNode() {
|
||||
return super.asAntlrNode();
|
||||
|
@ -5,7 +5,6 @@
|
||||
package net.sourceforge.pmd.lang.swift.ast;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.impl.antlr4.BaseAntlrTerminalNode;
|
||||
@ -28,8 +27,4 @@ public final class SwiftTerminalNode extends BaseAntlrTerminalNode<SwiftNode> im
|
||||
return SwiftParser.DICO.getXPathNameOfToken(getFirstAntlrToken().getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
|
||||
return visitor.visitTerminal(asAntlrNode());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.swift.ast;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.AstVisitorBase;
|
||||
|
||||
/**
|
||||
* Base class for swift visitors.
|
||||
*/
|
||||
public abstract class SwiftVisitorBase<P, R> extends AstVisitorBase<P, R> implements SwiftVisitor<P, R> {
|
||||
|
||||
}
|
@ -7,11 +7,12 @@ package net.sourceforge.pmd.lang.swift.rule.bestpractices;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.ast.AstVisitor;
|
||||
import net.sourceforge.pmd.lang.swift.AbstractSwiftRule;
|
||||
import net.sourceforge.pmd.lang.swift.ast.SwiftBaseVisitor;
|
||||
import net.sourceforge.pmd.lang.swift.ast.SwiftParser;
|
||||
import net.sourceforge.pmd.lang.swift.ast.SwiftParser.FunctionDeclarationContext;
|
||||
import net.sourceforge.pmd.lang.swift.ast.SwiftParser.InitializerDeclarationContext;
|
||||
import net.sourceforge.pmd.lang.swift.ast.SwiftVisitorBase;
|
||||
|
||||
public class UnavailableFunctionRule extends AbstractSwiftRule {
|
||||
|
||||
@ -25,11 +26,11 @@ public class UnavailableFunctionRule extends AbstractSwiftRule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SwiftBaseVisitor<Void> buildVisitor(RuleContext ruleCtx) {
|
||||
return new SwiftBaseVisitor<Void>() {
|
||||
public AstVisitor<RuleContext, ?> buildVisitor() {
|
||||
return new SwiftVisitorBase<RuleContext, Void>() {
|
||||
|
||||
@Override
|
||||
public Void visitFunctionDeclaration(final FunctionDeclarationContext ctx) {
|
||||
public Void visitFunctionDeclaration(final FunctionDeclarationContext ctx, RuleContext ruleCtx) {
|
||||
if (ctx == null) {
|
||||
return null;
|
||||
}
|
||||
@ -45,7 +46,7 @@ public class UnavailableFunctionRule extends AbstractSwiftRule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitInitializerDeclaration(final InitializerDeclarationContext ctx) {
|
||||
public Void visitInitializerDeclaration(final InitializerDeclarationContext ctx, RuleContext ruleCtx) {
|
||||
if (ctx == null) {
|
||||
return null;
|
||||
}
|
||||
|
Reference in New Issue
Block a user