diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java index 549f735ca3..0a2526298a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java @@ -5,6 +5,9 @@ package net.sourceforge.pmd.lang.ast.impl.antlr4; import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import java.util.stream.Stream; import org.antlr.v4.runtime.ParserRuleContext; @@ -35,10 +38,13 @@ public class AntlrNameDictionary { for (int i = 0; i < nonTermXpathNames.length; i++) { nonTermXpathNames[i] = StringUtils.capitalize(ruleNames[i]); } + Set seen = new HashSet<>(); + Collections.addAll(seen, ruleNames); // terminal names terminalXPathNames = new String[vocab.getMaxTokenType()]; - for (int i = 0; i < terminalXPathNames.length; i++) { + terminalXPathNames[0] = "Invalid"; // See Token.INVALID_TYPE + for (int i = Token.MIN_USER_TOKEN_TYPE; i < terminalXPathNames.length; i++) { String name = vocab.getSymbolicName(i); @@ -49,8 +55,8 @@ public class AntlrNameDictionary { // cleanup literal name, Antlr surrounds the image with single quotes name = name.substring(1, name.length() - 1); - if (!StringUtils.isAlphanumeric(name)) { - name = maybePunctName(name); + if (!name.matches("[a-zA-Z][\\w_-]+")) { // not alphanum + name = nonAlphaNumName(name); } // otherwise something like "final" } } @@ -60,7 +66,8 @@ public class AntlrNameDictionary { String finalName = "T-" + name; - assert finalName.matches("[a-zA-Z][\\w_-]+"); // must be a valid xpath name + assert finalName.matches("[a-zA-Z][\\w_-]+") : "Not a valid XPath name " + finalName; + assert seen.add(finalName) : "Duplicate XPath name " + finalName; terminalXPathNames[i] = finalName; } @@ -74,7 +81,7 @@ public class AntlrNameDictionary { return vocabulary; } - protected @Nullable String maybePunctName(String s) { + protected @Nullable String nonAlphaNumName(String s) { // these are hardcoded, but it's overridable // here we try to avoid semantic overtones, because // a-priori the same terminal may mean several things @@ -107,7 +114,6 @@ public class AntlrNameDictionary { case "@": return "at-symbol"; case "$": return "dollar"; - case "&": return "amp"; case "\\": return "backslash"; case "/": return "slash"; @@ -115,6 +121,7 @@ public class AntlrNameDictionary { case "`": return "backtick"; case "'": return "squote"; case "\"": return "dquote"; + case "\"\"\"": return "triple-quote"; case ">": return "gt"; case ">=": return "ge"; @@ -131,6 +138,11 @@ public class AntlrNameDictionary { case "===": return "triple-eq"; case "!=": return "not-eq"; + case "&": return "amp"; + case "&&": return "double-amp"; + case "|": return "pipe"; + case "||": return "double-pipe"; + case "*": return "star"; case "**": return "double-star"; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java index 5e2af9d2d8..aec3f91a37 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java @@ -41,7 +41,9 @@ public abstract class BaseAntlrInnerNode> extends BaseA @SuppressWarnings("unchecked") public N getChild(int index) { if (0 <= index && index < getNumChildren()) { - return (N) antlrNode.getChild(index).getPmdNode(); + N pmdNode = (N) antlrNode.getChild(index).getPmdNode(); + assert pmdNode.getIndexInParent() == index; + return pmdNode; } throw new IndexOutOfBoundsException("Index " + index + ", numChildren " + getNumChildren()); } diff --git a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 index 23d53dbf8d..da12f70b67 100644 --- a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 +++ b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 @@ -40,7 +40,7 @@ import net.sourceforge.pmd.lang.ast.impl.antlr4.*; @parser::members { - static final AntlrNameDictionary DICO = new AntlrNameDictionary(VOCABULARY, ruleNames); + static final AntlrNameDictionary DICO = new SwiftNameDictionary(VOCABULARY, ruleNames); @Override public SwiftTerminalNode createPmdTerminal(ParserRuleContext parent, Token t) { diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNameDictionary.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNameDictionary.java new file mode 100644 index 0000000000..7d1bcb6348 --- /dev/null +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNameDictionary.java @@ -0,0 +1,42 @@ +/* + * 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.Vocabulary; +import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.nullness.qual.Nullable; + +import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrNameDictionary; + + +final class SwiftNameDictionary extends AntlrNameDictionary { + + public SwiftNameDictionary(Vocabulary vocab, String[] ruleNames) { + super(vocab, ruleNames); + } + + @Override + protected @Nullable String nonAlphaNumName(String name) { + { + String sup = super.nonAlphaNumName(name); + if (sup != null) { + return sup; + } + } + + if (name.charAt(0) == '#' && StringUtils.isAlphanumeric(name.substring(1))) { + return "directive-" + name.substring(1); + } + + switch (name) { + case "unowned(safe)": return "unowned-safe"; + case "unowned(unsafe)": return "unowned-unsafe"; + case "getter:": return "getter"; + case "setter:": return "setter"; + case "OSXApplicationExtension\u00AD": return "OSXApplicationExtension-"; + default: return null; + } + } +}