diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java index 4bcb8f7423..b1456b5754 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java @@ -120,25 +120,21 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery { assert rootElementNode != null : "Cannot find " + node; final XPathDynamicContext xpathDynamicContext = createDynamicContext(rootElementNode); - final List nodes = new LinkedList<>(); + final List results = new LinkedList<>(); List expressions = getXPathExpressionForNodeOrDefault(node.getXPathNodeName()); for (Expression expression : expressions) { SequenceIterator iterator = expression.iterate(xpathDynamicContext.getXPathContextObject()); Item current = iterator.next(); while (current != null) { - nodes.add((ElementNode) current); + if (current instanceof ElementNode) { + results.add((Node) ((ElementNode) current).getUnderlyingNode()); + } else { + throw new RuntimeException("XPath rule expression returned a non-node (" + current.getClass() + "): " + current); + } current = iterator.next(); } } - /* - Map List of Saxon Nodes -> List of AST Nodes, which were detected to match the XPath expression - (i.e. violation found) - */ - final List results = new ArrayList<>(nodes.size()); - for (final ElementNode elementNode : nodes) { - results.add((Node) elementNode.getUnderlyingNode()); - } Collections.sort(results, RuleChainAnalyzer.documentOrderComparator()); return results; } catch (final XPathException e) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQueryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQueryTest.java index 0920d7c4e4..457ccdd6a0 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQueryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQueryTest.java @@ -9,8 +9,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.hamcrest.CoreMatchers; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.DummyNodeWithListAndEnum; @@ -22,6 +25,9 @@ import net.sf.saxon.expr.Expression; public class SaxonXPathRuleQueryTest { + @Rule + public final ExpectedException expected = ExpectedException.none(); + @Test public void testListAttribute() { DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); @@ -37,6 +43,18 @@ public class SaxonXPathRuleQueryTest { assertQuery(0, "//dummyNode[@EmptyList = (\"A\")]", dummy); } + @Test + public void testInvalidReturn() { + DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); + + + expected.expect(RuntimeException.class); + expected.expectMessage(CoreMatchers.containsString("XPath rule expression returned a non-node")); + expected.expectMessage(CoreMatchers.containsString("Int64Value")); + + createQuery("1+2").evaluate(dummy, new RuleContext()); + } + @Test public void ruleChainVisits() { SaxonXPathRuleQuery query = createQuery("//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = false()] | //dummyNode");