diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java index 75ca4b7a85..ad80a49d1f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java @@ -24,6 +24,7 @@ public abstract class AbstractNode implements Node { protected Node parent; protected Node[] children; + protected int childIndex; protected int id; private String image; @@ -76,6 +77,13 @@ public abstract class AbstractNode implements Node { children = newChildren; } children[index] = child; + child.jjtSetChildIndex(index); + } + public void jjtSetChildIndex(int index) { + childIndex = index; + } + public int jjtGetChildIndex() { + return childIndex; } public Node jjtGetChild(int index) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java index df88956992..31775d8c35 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java @@ -44,6 +44,16 @@ public interface Node { */ void jjtAddChild(Node child, int index); + /** + * Sets the index of this node from the perspective of its parent. + * This means: this.jjtGetParent().jjtGetChild(index) == this. + * + * @param index the child index + */ + void jjtSetChildIndex(int index); + + int jjtGetChildIndex(); + /** * This method returns a child node. The children are numbered * from zero, left to right. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java index 3987f5b1a8..cdac2eeda2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java @@ -43,7 +43,7 @@ public abstract class NodeIterator implements Iterator { protected Node getPreviousSibling(Node contextNode) { Node parentNode = contextNode.jjtGetParent(); if (parentNode != null) { - int prevPosition = getPositionFromParent(contextNode) - 1; + int prevPosition = contextNode.jjtGetChildIndex() - 1; if (prevPosition >= 0) { return parentNode.jjtGetChild(prevPosition); } @@ -51,20 +51,10 @@ public abstract class NodeIterator implements Iterator { return null; } - private int getPositionFromParent(Node contextNode) { - Node parentNode = contextNode.jjtGetParent(); - for (int i = 0; i < parentNode.jjtGetNumChildren(); i++) { - if (parentNode.jjtGetChild(i) == contextNode) { - return i; - } - } - throw new RuntimeException("Node was not a child of it's parent ???"); - } - protected Node getNextSibling(Node contextNode) { Node parentNode = contextNode.jjtGetParent(); if (parentNode != null) { - int nextPosition = getPositionFromParent(contextNode) + 1; + int nextPosition = contextNode.jjtGetChildIndex() + 1; if (nextPosition < parentNode.jjtGetNumChildren()) { return parentNode.jjtGetChild(nextPosition); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/AbstractScope.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/AbstractScope.java index 6e9c94da7a..8f39061f06 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/AbstractScope.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/AbstractScope.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.symboltable; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -15,7 +16,9 @@ import java.util.Map; public abstract class AbstractScope implements Scope { private Scope parent; - private Map> nameDeclarations = new LinkedHashMap>(); + /** Stores the name declaration already sorted by class. */ + private Map, Map>> nameDeclarations = + new LinkedHashMap, Map>>(); @Override public Scope getParent() { @@ -29,25 +32,26 @@ public abstract class AbstractScope implements Scope { @Override public Map> getDeclarations() { - return nameDeclarations; + Map> result = new LinkedHashMap>(); + for (Map> e : nameDeclarations.values()) { + result.putAll(e); + } + return result; } @Override public Map> getDeclarations(Class clazz) { - Map> result = new LinkedHashMap>(); - for (Map.Entry> e : nameDeclarations.entrySet()) { - if (clazz.isAssignableFrom(e.getKey().getClass())) { - @SuppressWarnings("unchecked") // it's assignable from, so should be ok - T cast = (T)e.getKey(); - result.put(cast, e.getValue()); - } + @SuppressWarnings("unchecked") + Map> result = (Map>)nameDeclarations.get(clazz); + if (result == null) { + result = new LinkedHashMap>(); } return result; } @Override public boolean contains(NameOccurrence occ) { - for (NameDeclaration d : nameDeclarations.keySet()) { + for (NameDeclaration d : getDeclarations().keySet()) { if (d.getImage().equals(occ.getImage())) { return true; } @@ -57,7 +61,12 @@ public abstract class AbstractScope implements Scope { @Override public void addDeclaration(NameDeclaration declaration) { - nameDeclarations.put(declaration, new ArrayList()); + Map> declarationsPerClass = nameDeclarations.get(declaration.getClass()); + if (declarationsPerClass == null) { + declarationsPerClass = new HashMap>(); + nameDeclarations.put(declaration.getClass(), declarationsPerClass); + } + declarationsPerClass.put(declaration, new ArrayList()); } @Override @@ -78,7 +87,7 @@ public abstract class AbstractScope implements Scope { @Override public NameDeclaration addNameOccurrence(NameOccurrence occurrence) { NameDeclaration result = null; - for (Map.Entry> e : nameDeclarations.entrySet()) { + for (Map.Entry> e : getDeclarations().entrySet()) { if (e.getKey().getImage().equals(occurrence.getImage())) { result = e.getKey(); e.getValue().add(occurrence); diff --git a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/XmlNodeInvocationHandler.java b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/XmlNodeInvocationHandler.java index c59a10c40f..299691f9e5 100644 --- a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/XmlNodeInvocationHandler.java +++ b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/XmlNodeInvocationHandler.java @@ -21,6 +21,7 @@ import net.sourceforge.pmd.util.CompoundIterator; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.w3c.dom.Text; public class XmlNodeInvocationHandler implements InvocationHandler { @@ -41,6 +42,15 @@ public class XmlNodeInvocationHandler implements InvocationHandler { return node.hasChildNodes() ? node.getChildNodes().getLength() : 0; } else if ("jjtGetChild".equals(method.getName())) { return parser.createProxy(node.getChildNodes().item(((Integer) args[0]).intValue())); + } else if ("jjtGetChildIndex".equals(method.getName())) { + Node parent = node.getParentNode(); + NodeList childNodes = parent.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + if (node == childNodes.item(i)) { + return i; + } + } + throw new IllegalStateException("This node is not a child of its parent: " + node); } else if ("getImage".equals(method.getName())) { if (node instanceof Text) { return ((Text) node).getData(); diff --git a/src/site/markdown/overview/changelog.md b/src/site/markdown/overview/changelog.md index 9e55724172..638ca4b34e 100644 --- a/src/site/markdown/overview/changelog.md +++ b/src/site/markdown/overview/changelog.md @@ -32,3 +32,4 @@ * [#1298](https://sourceforge.net/p/pmd/bugs/1298/): Member variable int type with value 0xff000000 causes processing error * [#1299](https://sourceforge.net/p/pmd/bugs/1299/): MethodReturnsInternalArray false positive * [#1306](https://sourceforge.net/p/pmd/bugs/1306/): False positive on duplicate when using static imports +* [#1308](https://sourceforge.net/p/pmd/bugs/1308/): PMD runs endlessly on some generated files