Preserve terminal nodes

This commit is contained in:
Clément Fournier
2020-04-29 12:12:29 +02:00
parent 97fef3fbd9
commit f7560ed9fb
26 changed files with 5488 additions and 313 deletions

View File

@ -0,0 +1,38 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.impl.antlr4;
/**
*
*/
public abstract class AbstractAntlrInnerNode<T extends AntlrParseTreeBase, N extends AntlrNode<N>>
extends AbstractAntlrNode<T, N> {
protected AbstractAntlrInnerNode(T parseTree) {
super(parseTree);
}
@Override
public int getBeginLine() {
return getParseTree().start.getLine(); // This goes from 1 to n
}
@Override
public int getEndLine() {
// FIXME this is not the end line if the stop token spans several lines
return getParseTree().stop.getLine();
}
@Override
public int getBeginColumn() {
return AntlrUtils.getBeginColumn(getParseTree().start);
}
@Override
public int getEndColumn() {
return AntlrUtils.getEndColumn(getParseTree().stop);
}
}

View File

@ -5,16 +5,12 @@
package net.sourceforge.pmd.lang.ast.impl.antlr4;
import net.sourceforge.pmd.lang.ast.impl.AbstractNode;
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
/**
*
*/
public abstract class AbstractAntlrNode<
B extends AbstractAntlrNode<B, ?, N>,
T extends AntlrParseTreeBase,
N extends GenericNode<N>
> extends AbstractNode<B, N> {
public abstract class AbstractAntlrNode<T, N extends AntlrNode<N>>
extends AbstractNode<AbstractAntlrNode<?, N>, N> implements AntlrNode<N> {
private final T parseTree;
@ -22,14 +18,11 @@ public abstract class AbstractAntlrNode<
this.parseTree = parseTree;
}
@Override
protected void addChild(B child, int index) {
protected void addChild(AbstractAntlrNode<?, N> child, int index) {
super.addChild(child, index);
}
public abstract <P, R> R acceptVisitor(AntlrTreeVisitor<P, R, ?> visitor, P data);
public T getParseTree() {
return parseTree;
}
@ -41,25 +34,5 @@ public abstract class AbstractAntlrNode<
'}';
}
@Override
public int getBeginLine() {
return parseTree.start.getLine(); // This goes from 1 to n
}
@Override
public int getEndLine() {
// FIXME this is not the end line if the stop token spans several lines
return parseTree.stop.getLine();
}
@Override
public int getBeginColumn() {
return AntlrUtils.getBeginColumn(parseTree.start);
}
@Override
public int getEndColumn() {
return AntlrUtils.getEndColumn(parseTree.stop);
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.TerminalNode;
/**
*
*/
public abstract class AbstractAntlrTerminalNode<N extends AntlrNode<N>>
extends AbstractAntlrNode<TerminalNode, N> {
protected AbstractAntlrTerminalNode(TerminalNode parseTree) {
super(parseTree);
}
@Override
public int getBeginLine() {
return getParseTree().getSymbol().getLine(); // This goes from 1 to n
}
@Override
public int getEndLine() {
// FIXME this is not the end line if the stop token spans several lines
return getParseTree().getSymbol().getLine();
}
@Override
public int getBeginColumn() {
return AntlrUtils.getBeginColumn(getParseTree().getSymbol());
}
@Override
public int getEndColumn() {
return AntlrUtils.getEndColumn(getParseTree().getSymbol());
}
}

View File

@ -15,7 +15,6 @@ import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.ast.RootNode;
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
/**
* Generic Antlr parser adapter for all Antlr parsers. This wraps a parser
@ -25,9 +24,8 @@ import net.sourceforge.pmd.lang.ast.impl.GenericNode;
* @param <R> Type of the root node
*/
public abstract class AntlrBaseParser<
N extends GenericNode<N>,
B extends AbstractAntlrNode<B, ?, N>,
R extends AbstractAntlrNode<B, ?, N> & RootNode
N extends AntlrNode<N>,
R extends AbstractAntlrNode<?, N> & RootNode
> implements Parser {
protected final ParserOptions parserOptions;

View File

@ -27,7 +27,7 @@ public abstract class AntlrBaseRule extends AbstractRule {
for (Node node : nodes) {
assert node instanceof AbstractAntlrNode : "Incorrect node type " + node + " passed to " + this;
((AbstractAntlrNode<?, ?, ?>) node).acceptVisitor(visitor, ctx);
((AbstractAntlrNode<?, ?>) node).acceptVisitor(visitor, ctx);
}
}

View File

@ -0,0 +1,15 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.impl.antlr4;
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
/**
*
*/
public interface AntlrNode<N extends GenericNode<N>> extends GenericNode<N> {
<P, R> R acceptVisitor(AntlrTreeVisitor<P, R, ?> visitor, P data);
}

View File

@ -12,7 +12,7 @@ import org.antlr.v4.runtime.ParserRuleContext;
*/
public abstract class AntlrParseTreeBase extends ParserRuleContext {
AbstractAntlrNode<?, ?, ?> pmdNode;
AntlrNode<?> pmdNode;
protected AntlrParseTreeBase() {

View File

@ -16,7 +16,7 @@ import org.antlr.v4.runtime.tree.TerminalNode;
/**
* Don't extend me, compose me.
*/
public class AntlrTreeBuilderState<B extends AbstractAntlrNode<B, ?, ?>> implements ParseTreeListener {
public class AntlrTreeBuilderListener<B extends AbstractAntlrNode<?, N>, N extends AntlrNode<N>> implements ParseTreeListener {
private final ParseTreeVisitor<B> nodeFactory;
@ -26,7 +26,7 @@ public class AntlrTreeBuilderState<B extends AbstractAntlrNode<B, ?, ?>> impleme
private int sp = 0;
private int mk = 0;
public AntlrTreeBuilderState(ParseTreeVisitor<B> nodeFactory) {
public AntlrTreeBuilderListener(ParseTreeVisitor<B> nodeFactory) {
this.nodeFactory = nodeFactory;
}
@ -36,7 +36,8 @@ public class AntlrTreeBuilderState<B extends AbstractAntlrNode<B, ?, ?>> impleme
@Override
public void visitTerminal(TerminalNode node) {
B toPush = nodeFactory.visitTerminal(node);
pushNode(toPush);
}
@Override
@ -46,6 +47,10 @@ public class AntlrTreeBuilderState<B extends AbstractAntlrNode<B, ?, ?>> impleme
@Override
public void enterEveryRule(ParserRuleContext ctx) {
enterNode();
}
private void enterNode() {
marks.push(mk);
mk = sp;
}
@ -55,6 +60,7 @@ public class AntlrTreeBuilderState<B extends AbstractAntlrNode<B, ?, ?>> impleme
B newNode = nodeFactory.visit(ctx);
((AntlrParseTreeBase) ctx).pmdNode = newNode;
int arity = nodeArity();
mk = marks.pop();
while (arity-- > 0) {

View File

@ -38,7 +38,6 @@ import net.sourceforge.pmd.lang.ast.impl.antlr4.*;
}
@parser::members {
public static final AntlrNameDictionary DICO = new AntlrNameDictionary(VOCABULARY, ruleNames);

View File

@ -7,12 +7,12 @@ package net.sourceforge.pmd.lang.swift;
import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler;
import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.swift.ast.SwiftParserAdapter;
import net.sourceforge.pmd.lang.swift.ast.SwiftParser;
public class SwiftHandler extends AbstractPmdLanguageVersionHandler {
@Override
public Parser getParser(final ParserOptions parserOptions) {
return new SwiftParserAdapter(parserOptions);
return new SwiftParser(parserOptions);
}
}

View File

@ -0,0 +1,23 @@
/*
* 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.swift.ast.SwiftTreeParser.IdentifierContext;
public final class SwIdentifier extends SwiftInnerNode<IdentifierContext> {
SwIdentifier(IdentifierContext parseTreeNode) {
super(parseTreeNode);
}
public String getName() {
return getParseTree().getText(); // single token
}
@Override
public <P, R> R acceptVisitor(SwiftVisitor<P, R> visitor, P data) {
return visitor.visitIdent(this, data);
}
}

View File

@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.swift.ast;
import net.sourceforge.pmd.lang.ast.RootNode;
import net.sourceforge.pmd.lang.swift.ast.SwiftTreeParser.TopLevelContext;
public final class SwiftRootNode extends SwiftNodeImpl<TopLevelContext> implements RootNode {
public final class SwRootNode extends SwiftInnerNode<TopLevelContext> implements RootNode {
public SwiftRootNode(TopLevelContext parseTreeNode) {
SwRootNode(TopLevelContext parseTreeNode) {
super(parseTreeNode);
}

View File

@ -4,32 +4,22 @@
package net.sourceforge.pmd.lang.swift.ast;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AbstractAntlrInnerNode;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AbstractAntlrNode;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrParseTreeBase;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTreeVisitor;
/**
*
*/
public class SwiftNodeImpl<T extends AntlrParseTreeBase>
extends AbstractAntlrNode<SwiftNodeImpl<?>, T, SwiftNode<?>>
public class SwiftInnerNode<T extends AntlrParseTreeBase>
extends AbstractAntlrInnerNode<T, SwiftNode<?>>
implements SwiftNode<T> {
SwiftNodeImpl(T parseTreeNode) {
SwiftInnerNode(T parseTreeNode) {
super(parseTreeNode);
}
@Override
protected void addChild(SwiftNodeImpl<?> child, int index) {
super.addChild(child, index);
}
@Override
public final <P, R> R acceptVisitor(AntlrTreeVisitor<P, R, ?> visitor, P data) {
if (visitor instanceof SwiftVisitor) {
return acceptVisitor((SwiftVisitor<P, R>) visitor, data);
}
throw new IllegalArgumentException("Cannot accept visitor " + visitor);
protected void addChild(AbstractAntlrNode<?, SwiftNode<?>> child, int index) {
super.addChild(child, index);
}
@Override

View File

@ -4,19 +4,27 @@
package net.sourceforge.pmd.lang.swift.ast;
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrParseTreeBase;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrNode;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTreeVisitor;
/**
* Supertype of all swift nodes.
*/
public interface SwiftNode<T extends AntlrParseTreeBase> extends GenericNode<SwiftNode<?>> {
public interface SwiftNode<T> extends AntlrNode<SwiftNode<?>> {
T getParseTree();
<P, R> R acceptVisitor(SwiftVisitor<P, R> visitor, P data);
@Override
default <P, R> R acceptVisitor(AntlrTreeVisitor<P, R, ?> visitor, P data) {
if (visitor instanceof SwiftVisitor) {
return acceptVisitor((SwiftVisitor<P, R>) visitor, data);
}
throw new IllegalArgumentException("Cannot accept visitor " + visitor);
}
}

View File

@ -5,12 +5,15 @@
package net.sourceforge.pmd.lang.swift.ast;
import org.antlr.v4.runtime.tree.RuleNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AbstractAntlrNode;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrParseTreeBase;
import net.sourceforge.pmd.lang.swift.ast.SwiftTreeParser.IdentifierContext;
import net.sourceforge.pmd.lang.swift.ast.SwiftTreeParser.TopLevelContext;
final class SwiftNodeFactory extends SwiftTreeBaseVisitor<SwiftNodeImpl<?>> {
final class SwiftNodeFactory extends SwiftTreeBaseVisitor<AbstractAntlrNode<?, SwiftNode<?>>> {
static final SwiftNodeFactory INSTANCE = new SwiftNodeFactory();
@ -19,13 +22,23 @@ final class SwiftNodeFactory extends SwiftTreeBaseVisitor<SwiftNodeImpl<?>> {
}
@Override
public SwiftNodeImpl<?> visitTopLevel(TopLevelContext ctx) {
return new SwiftRootNode(ctx);
public SwiftTerminal visitTerminal(TerminalNode node) {
return new SwiftTerminal(node);
}
@Override
public SwiftNodeImpl<?> visitChildren(RuleNode node) {
public SwiftInnerNode<?> visitIdentifier(IdentifierContext ctx) {
return new SwIdentifier(ctx);
}
@Override
public SwiftInnerNode<?> visitTopLevel(TopLevelContext ctx) {
return new SwRootNode(ctx);
}
@Override
public SwiftInnerNode<?> visitChildren(RuleNode node) {
// default visit
return new SwiftNodeImpl<>((AntlrParseTreeBase) node);
return new SwiftInnerNode<>((AntlrParseTreeBase) node);
}
}

View File

@ -10,24 +10,24 @@ import org.antlr.v4.runtime.Lexer;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrBaseParser;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTreeBuilderState;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTreeBuilderListener;
/**
* Adapter for the SwiftParser.
*/
public final class SwiftParserAdapter extends AntlrBaseParser<SwiftNode<?>, SwiftNodeImpl<?>, SwiftRootNode> {
public final class SwiftParser extends AntlrBaseParser<SwiftNode<?>, SwRootNode> {
public SwiftParserAdapter(final ParserOptions parserOptions) {
public SwiftParser(final ParserOptions parserOptions) {
super(parserOptions);
}
@Override
protected SwiftRootNode parse(final Lexer lexer) {
protected SwRootNode parse(final Lexer lexer) {
SwiftTreeParser parser = new SwiftTreeParser(new CommonTokenStream(lexer));
AntlrTreeBuilderState<?> listener = new AntlrTreeBuilderState<>(SwiftNodeFactory.INSTANCE);
AntlrTreeBuilderListener<?, ?> listener = new AntlrTreeBuilderListener<>(SwiftNodeFactory.INSTANCE);
parser.addParseListener(listener);
parser.topLevel();
return (SwiftRootNode) listener.top();
return (SwRootNode) listener.top();
}
@Override

View File

@ -0,0 +1,27 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.swift.ast;
import org.antlr.v4.runtime.tree.TerminalNode;
import net.sourceforge.pmd.lang.ast.impl.antlr4.AbstractAntlrTerminalNode;
public final class SwiftTerminal extends AbstractAntlrTerminalNode<SwiftNode<?>> implements SwiftNode<TerminalNode> {
SwiftTerminal(TerminalNode parseTreeNode) {
super(parseTreeNode);
}
@Override
public String getXPathNodeName() {
return SwiftTreeParser.DICO.getXPathNameOfToken(getParseTree().getSymbol().getType());
}
@Override
public <P, R> R acceptVisitor(SwiftVisitor<P, R> visitor, P data) {
return visitor.visitTerminal(this, data);
}
}

View File

@ -11,10 +11,24 @@ import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTreeVisitor;
*/
public interface SwiftVisitor<P, R> extends AntlrTreeVisitor<P, R, SwiftNode<?>> {
default R visitRoot(SwiftRootNode node, P data) {
default R visitTerminal(SwiftTerminal node, P data) {
return visitAnyNode(node, data);
}
default R visitInnerNode(SwiftInnerNode<?> node, P data) {
return visitAnyNode(node, data);
}
default R visitRoot(SwRootNode node, P data) {
return visitInnerNode(node, data);
}
default R visitIdent(SwIdentifier node, P data) {
return visitInnerNode(node, data);
}
}

View File

@ -8,6 +8,7 @@ import java.util.List;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.swift.AbstractSwiftRule;
import net.sourceforge.pmd.lang.swift.ast.SwiftInnerNode;
import net.sourceforge.pmd.lang.swift.ast.SwiftNode;
import net.sourceforge.pmd.lang.swift.ast.SwiftTreeParser;
import net.sourceforge.pmd.lang.swift.ast.SwiftTreeParser.AttributeContext;
@ -34,8 +35,13 @@ public class UnavailableFunctionRule extends AbstractSwiftRule {
return new SwiftVisitor<RuleContext, Void>() {
@Override
@SuppressWarnings("unchecked")
public Void visitAnyNode(SwiftNode<?> swiftNode, RuleContext data) {
return null;
}
@Override
@SuppressWarnings("unchecked")
public Void visitInnerNode(SwiftInnerNode<?> swiftNode, RuleContext data) {
switch (swiftNode.getParseTree().getRuleIndex()) {
case SwiftTreeParser.RULE_functionDeclaration:
return visitFunctionDeclaration((SwiftNode<FunctionDeclarationContext>) swiftNode, data);

View File

@ -26,9 +26,9 @@ Rules which enforce generally accepted best practices.
<property name="version" value="2.0" />
<property name="xpath">
<value>
//VariableDeclarationHead/Attributes/Attribute[T-at-symbol and AttributeName/*/T-Identifier/@Text = "IBOutlet"]
//VariableDeclarationHead/Attributes/Attribute[AttributeName/Identifier[@Name = "IBOutlet"]]
|
//FunctionHead/Attributes/Attribute[T-at-symbol and AttributeName/*/T-Identifier/@Text = "IBAction"]
//FunctionHead/Attributes/Attribute[AttributeName/Identifier[@Name = "IBAction"]]
</value>
</property>
</properties>

View File

@ -25,7 +25,7 @@
<property name="xpath">
<value>
<![CDATA[
//TypeCastingOperator[T-bang]
//TypeCastingOperator[T-as and T-bang]
]]>
</value>
</property>

View File

@ -16,4 +16,9 @@ public class SwiftParserTests extends BaseSwiftTreeDumpTest {
doTest("Simple");
}
@Test
public void testBtree() {
doTest("BTree");
}
}

View File

@ -12,13 +12,13 @@ import net.sourceforge.pmd.lang.swift.SwiftLanguageModule;
/**
*
*/
public class SwiftParsingHelper extends BaseParsingHelper<SwiftParsingHelper, SwiftRootNode> {
public class SwiftParsingHelper extends BaseParsingHelper<SwiftParsingHelper, SwRootNode> {
public static final SwiftParsingHelper DEFAULT = new SwiftParsingHelper(Params.getDefaultNoProcess());
public SwiftParsingHelper(@NotNull Params params) {
super(SwiftLanguageModule.NAME, SwiftRootNode.class, params);
super(SwiftLanguageModule.NAME, SwRootNode.class, params);
}
@NotNull

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff