Update saxon version

Remove Jaxen, port function defs

Use enum to represent XPath version

Move to internal package

Fix style

Refactor functions
This commit is contained in:
Clément Fournier
2018-11-03 07:10:13 +01:00
parent 0b776f338a
commit cda02a2754
49 changed files with 951 additions and 2115 deletions

View File

@ -54,13 +54,6 @@
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.saxon</groupId>
<artifactId>saxon</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@ -126,8 +126,8 @@
<artifactId>javacc</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.saxon</groupId>
<artifactId>saxon</artifactId>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@ -149,14 +149,6 @@
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>net.sourceforge.saxon</groupId>
<artifactId>saxon</artifactId>
<classifier>dom</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>

View File

@ -20,7 +20,6 @@ import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.ast.RootNode;
import net.sourceforge.pmd.lang.xpath.Initializer;
public class SourceCodeProcessor {
@ -80,9 +79,6 @@ public class SourceCodeProcessor {
public void processSourceCode(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) throws PMDException {
determineLanguage(ctx);
// make sure custom XPath functions are initialized
Initializer.initialize();
// Coarse check to see if any RuleSet applies to file, will need to do a finer RuleSet specific check later
if (ruleSets.applies(ctx.getSourceCodeFile())) {
if (isCacheUpToDate(ctx)) {

View File

@ -9,7 +9,6 @@ import java.util.List;
import net.sourceforge.pmd.annotation.Experimental;
import net.sourceforge.pmd.lang.ast.AstProcessingStage;
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
@ -30,7 +29,7 @@ public interface LanguageVersionHandler {
* Get the XPathHandler.
*/
default XPathHandler getXPathHandler() {
return new DefaultASTXPathHandler();
return XPathHandler.noFunctionDefinitions();
}

View File

@ -4,40 +4,33 @@
package net.sourceforge.pmd.lang;
import org.jaxen.Navigator;
import java.util.Collections;
import java.util.Set;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.xpath.Initializer;
import net.sourceforge.pmd.util.CollectionUtil;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.sxpath.IndependentContext;
/**
* Interface for performing Language specific XPath handling, such as
* initialization and navigation.
*/
@InternalApi
@Deprecated
public interface XPathHandler {
/**
* Initialize. This is intended to be called by {@link Initializer} to
* perform Language specific initialization.
*/
void initialize();
Set<ExtensionFunctionDefinition> getRegisteredExtensionFunctions();
static XPathHandler noFunctionDefinitions() {
return Collections::emptySet;
}
/**
* Initialize. This is intended to be called by {@link Initializer} to
* perform Language specific initialization for Saxon.
* Returns a default XPath handler.
*/
void initialize(IndependentContext context);
/**
* Get a Jaxen Navigator for this Language. May return <code>null</code> if
* there is no Jaxen Navigation for this language.
*
* @deprecated Support for Jaxen will be removed come 7.0.0. This isn't used
* anymore
*/
@Deprecated
Navigator getNavigator();
static XPathHandler getHandlerForFunctionDefs(ExtensionFunctionDefinition first, ExtensionFunctionDefinition... defs) {
Set<ExtensionFunctionDefinition> set = CollectionUtil.setOf(first, defs);
return () -> set;
}
}

View File

@ -1,38 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath;
import org.jaxen.Navigator;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.XPathHandler;
import net.sf.saxon.sxpath.IndependentContext;
@Deprecated
@InternalApi
public abstract class AbstractASTXPathHandler implements XPathHandler {
@Override
public Navigator getNavigator() {
return new DocumentNavigator();
}
public void initialize(IndependentContext context, Language language, Class<?> functionsClass) {
context.declareNamespace("pmd-" + language.getTerseName(), "java:" + functionsClass.getName());
}
@Override
public void initialize() {
// override if needed
}
@Override
public void initialize(IndependentContext context) {
// override if needed
}
}

View File

@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ast.xpath;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@ -50,6 +51,18 @@ public class Attribute {
}
/**
* Gets the generic type of the value of this attribute.
*/
public Type getType() {
return method == null ? String.class : method.getGenericReturnType();
}
public Class<?> getErasedType() {
return method == null ? String.class : method.getReturnType();
}
public String getName() {
return name;
}

View File

@ -1,25 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sf.saxon.sxpath.IndependentContext;
@Deprecated
@InternalApi
public class DefaultASTXPathHandler extends AbstractASTXPathHandler {
@Override
public void initialize() {
// override if needed
}
@Override
public void initialize(IndependentContext context) {
// override if needed
}
}

View File

@ -180,7 +180,7 @@ public class DocumentNavigator extends DefaultNavigator {
while (baseIterator.hasNext() && result == null) {
Attribute candidate = baseIterator.next();
// Calling getValue() here would break laziness
if (!List.class.isAssignableFrom(candidate.getType())) {
if (!List.class.isAssignableFrom(candidate.getErasedType())) {
result = candidate;
}
}

View File

@ -0,0 +1,32 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.internal;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.StructuredQName;
/**
* Base impl for an XPath function definition.
*
* @author Clément Fournier
* @since 7.0.0
*/
public abstract class AbstractXPathFunctionDef extends ExtensionFunctionDefinition {
private static final String PMD_URI_PREFIX = "http://pmd.sourceforge.net/";
private final StructuredQName qname;
protected AbstractXPathFunctionDef(String localName, String languageTerseName) {
String namespacePrefix = "pmd-" + languageTerseName;
String uri = PMD_URI_PREFIX + namespacePrefix;
this.qname = new StructuredQName(namespacePrefix, uri, localName);
}
@Override
public final StructuredQName getFunctionQName() {
return qname;
}
}

View File

@ -0,0 +1,120 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.internal;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.pattern.NodeTest;
import net.sf.saxon.tree.iter.AxisIterator;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.tree.wrapper.AbstractNodeWrapper;
import net.sf.saxon.type.SchemaType;
import net.sf.saxon.type.Type;
/**
* @author Clément Fournier
* @since 7.0.0
*/
public class AstAttributeWrapper extends AbstractNodeWrapper {
private final AstNodeWrapper parent;
private final Attribute attribute;
private final SchemaType schemaType;
AstAttributeWrapper(AstNodeWrapper parent, Attribute attribute) {
this.parent = parent;
this.attribute = attribute;
this.schemaType = DomainConversion.buildType(attribute.getType());
}
@Override
protected AxisIterator iterateAttributes(NodeTest nodeTest) {
return null;
}
@Override
protected AxisIterator iterateChildren(NodeTest nodeTest) {
return null;
}
@Override
protected AxisIterator iterateSiblings(NodeTest nodeTest, boolean forwards) {
return null;
}
@Override
protected AxisIterator iterateDescendants(NodeTest nodeTest, boolean includeSelf) {
return null;
}
@Override
public SchemaType getSchemaType() {
return schemaType;
}
@Override
public Attribute getUnderlyingNode() {
return attribute;
}
@Override
public int getNodeKind() {
return Type.ATTRIBUTE;
}
@Override
public int compareOrder(NodeInfo other) {
// attributes have no order in the xdm
return 0;
}
@Override
public String getLocalPart() {
return attribute.getName();
}
@Override
public String getURI() {
return "";
}
@Override
public String getPrefix() {
return "";
}
@Override
public NodeInfo getParent() {
return parent;
}
@Override
public void generateId(FastStringBuffer buffer) {
buffer.append(Integer.toString(hashCode()));
}
@Override
public CharSequence getStringValueCS() {
return attribute.getStringValue();
}
}

View File

@ -0,0 +1,46 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.internal;
import net.sourceforge.pmd.lang.ast.Node;
import net.sf.saxon.Configuration;
import net.sf.saxon.om.GenericTreeInfo;
/**
* A wrapper around the root node of an AST, implementing {@link net.sf.saxon.om.TreeInfo}.
*/
public final class AstDocument extends GenericTreeInfo {
private DeprecatedAttrLogger logger;
/**
* Builds an AstDocument, with the given node as the root.
*
* @param node The root AST Node.
* @param configuration Configuration of the run
*
* @see AstNodeWrapper
*/
public AstDocument(Node node, Configuration configuration) {
super(configuration);
setRootNode(new AstNodeWrapper(this, new IdGenerator(), null, node));
}
@Override
public AstNodeWrapper getRootNode() {
return (AstNodeWrapper) super.getRootNode();
}
public void setAttrCtx(DeprecatedAttrLogger attrCtx) {
this.logger = attrCtx;
}
public DeprecatedAttrLogger getLogger() {
return logger == null ? DeprecatedAttrLogger.noop() : logger;
}
}

View File

@ -0,0 +1,280 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.pattern.NodeTest;
import net.sf.saxon.tree.iter.AxisIterator;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.tree.util.Navigator.AxisFilter;
import net.sf.saxon.tree.wrapper.AbstractNodeWrapper;
import net.sf.saxon.type.Type;
/**
* A wrapper for Saxon around a Node.
*/
public final class AstNodeWrapper extends AbstractNodeWrapper {
private final AstNodeWrapper parent;
private final Node wrappedNode;
private final int id;
private final List<AstNodeWrapper> children;
private final Map<String, AstAttributeWrapper> attributes;
public AstNodeWrapper(AstDocument document,
IdGenerator idGenerator,
AstNodeWrapper parent,
Node wrappedNode) {
this.treeInfo = document;
this.parent = parent;
this.wrappedNode = wrappedNode;
this.id = idGenerator.getNextId();
this.children = new ArrayList<>(wrappedNode.jjtGetNumChildren());
for (int i = 0; i < wrappedNode.jjtGetNumChildren(); i++) {
children.add(new AstNodeWrapper(document, idGenerator, this, wrappedNode.jjtGetChild(i)));
}
Map<String, AstAttributeWrapper> atts = new HashMap<>();
Iterator<Attribute> it = wrappedNode.getXPathAttributesIterator();
while (it.hasNext()) {
Attribute next = it.next();
atts.put(next.getName(), new AstAttributeWrapper(this, next));
}
this.attributes = atts;
}
@Override
public AstDocument getTreeInfo() {
return (AstDocument) super.getTreeInfo();
}
@Override
public Node getUnderlyingNode() {
return wrappedNode;
}
@Override
public int getColumnNumber() {
return wrappedNode.getBeginColumn();
}
@Override
public int compareOrder(NodeInfo other) {
return Integer.compare(id, ((AstNodeWrapper) other).id);
}
private <T> AxisIterator mapIterator(Iterator<? extends T> it, Function<? super T, NodeInfo> map, NodeTest nodeTest) {
AxisIterator axisIterator = new AxisIterator() {
@Override
public NodeInfo next() {
return it.hasNext() ? map.apply(it.next()) : null;
}
@Override
public void close() {
// nothing to do
}
@Override
public int getProperties() {
return 0;
}
};
return nodeTest != null ? new AxisFilter(axisIterator, nodeTest) : axisIterator;
}
@Override
protected AxisIterator iterateAttributes(NodeTest nodeTest) {
return mapIterator(attributes.values().iterator(), Function.identity(), nodeTest);
}
@Override
protected AxisIterator iterateChildren(NodeTest nodeTest) {
return mapIterator(children.iterator(), Function.identity(), nodeTest);
}
private AxisIterator empty() {
return new AxisIterator() {
@Override
public NodeInfo next() {
return null;
}
@Override
public void close() {
// nothing to do
}
@Override
public int getProperties() {
return 0;
}
};
}
@Override
protected AxisIterator iterateSiblings(NodeTest nodeTest, boolean forwards) {
int startIdx = wrappedNode.getIndexInParent() + (forwards ? +1 : -1);
if (parent == null) {
return empty();
}
AxisIterator siblings = new AxisIterator() {
int curIdx = startIdx;
@Override
public NodeInfo next() {
if (!forwards && startIdx < 0
|| forwards && startIdx > parent.wrappedNode.jjtGetNumChildren()) {
return null;
}
AstNodeWrapper next = parent.children.get(curIdx);
curIdx += forwards ? +1 : -1;
return next;
}
@Override
public void close() {
// nothing to do
}
@Override
public int getProperties() {
return 0;
}
};
return nodeTest != null ? new AxisFilter(siblings, nodeTest) : siblings;
}
private Stream<AstNodeWrapper> streamDescendants() {
return Stream.concat(Stream.of(this), children.stream().flatMap(AstNodeWrapper::streamDescendants));
}
@Override
public String getAttributeValue(String uri, String local) {
AstAttributeWrapper attributeWrapper = attributes.get(local);
return attributeWrapper == null ? null : attributeWrapper.getStringValue();
}
@Override
protected AxisIterator iterateDescendants(NodeTest nodeTest, boolean includeSelf) {
AxisIterator descendants = mapIterator(streamDescendants().iterator(), Function.identity(), null);
if (!includeSelf) {
// skip one
descendants.next();
}
return nodeTest != null ? new AxisFilter(descendants, nodeTest) : descendants;
}
@Override
public int getLineNumber() {
return wrappedNode.getBeginLine();
}
@Override
public int getNodeKind() {
return parent == null ? Type.DOCUMENT : Type.ELEMENT;
}
@Override
public NodeInfo getRoot() {
return getTreeInfo().getRootNode();
}
@Override
public void generateId(FastStringBuffer buffer) {
buffer.append(Integer.toString(hashCode()));
}
public int getId() {
return id;
}
@Override
public String getLocalPart() {
return wrappedNode.getXPathNodeName();
}
@Override
public String getURI() {
return "";
}
@Override
public String getPrefix() {
return "";
}
@Override
public NodeInfo getParent() {
return parent;
}
@Override
public CharSequence getStringValueCS() {
return getStringValue();
}
@Override
public String toString() {
return "Wrapper[" + getLocalPart() + "]@" + hashCode();
}
}

View File

@ -0,0 +1,89 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.internal;
import java.util.regex.Pattern;
import net.sf.saxon.type.BuiltInAtomicType;
import net.sf.saxon.type.SchemaType;
import net.sf.saxon.value.AtomicValue;
import net.sf.saxon.value.BigIntegerValue;
import net.sf.saxon.value.BooleanValue;
import net.sf.saxon.value.DoubleValue;
import net.sf.saxon.value.FloatValue;
import net.sf.saxon.value.Int64Value;
import net.sf.saxon.value.StringValue;
import net.sf.saxon.value.UntypedAtomicValue;
/**
* @author Clément Fournier
* @since 7.0.0
*/
public final class DomainConversion {
private DomainConversion() {
}
public static SchemaType buildType(java.lang.reflect.Type type) {
switch (type.getTypeName()) {
case "java.lang.Integer":
case "java.lang.Long":
return BuiltInAtomicType.INTEGER;
case "java.lang.Double":
case "java.lang.Float":
return BuiltInAtomicType.DOUBLE;
case "java.lang.String":
case "java.lang.Character":
case "java.lang.Class":
case "java.util.regex.Pattern":
return BuiltInAtomicType.STRING;
default:
return BuiltInAtomicType.UNTYPED_ATOMIC;
}
}
/**
* Gets the Saxon representation of the parameter, if its type corresponds
* to an XPath 2.0 atomic datatype.
*
* @param value The value to convert
*
* @return The converted AtomicValue
*/
public static AtomicValue getAtomicRepresentation(final Object value) {
/*
FUTURE When supported, we should consider refactor this implementation to use Pattern Matching
(see http://openjdk.java.net/jeps/305) so that it looks clearer.
*/
if (value == null) {
return UntypedAtomicValue.ZERO_LENGTH_UNTYPED;
} else if (value instanceof String) {
return new StringValue((String) value);
} else if (value instanceof Boolean) {
return BooleanValue.get((Boolean) value);
} else if (value instanceof Integer) {
return Int64Value.makeIntegerValue((Integer) value);
} else if (value instanceof Long) {
return new BigIntegerValue((Long) value);
} else if (value instanceof Double) {
return new DoubleValue((Double) value);
} else if (value instanceof Character) {
return new StringValue(value.toString());
} else if (value instanceof Float) {
return new FloatValue((Float) value);
} else if (value instanceof Pattern) {
return new StringValue(String.valueOf(value));
} else {
// We could maybe use UntypedAtomicValue
throw new RuntimeException("Unable to create ValueRepresentation for value of type: " + value.getClass());
}
}
}

View File

@ -1,21 +1,17 @@
/**
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.saxon;
import net.sourceforge.pmd.annotation.InternalApi;
package net.sourceforge.pmd.lang.ast.xpath.internal;
/**
* This class is used to generate unique IDs for nodes.
*/
@Deprecated
@InternalApi
public class IdGenerator {
class IdGenerator {
private int id;
public int getNextId() {
int getNextId() {
return id++;
}
}

View File

@ -1,283 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.saxon;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sf.saxon.Configuration;
import net.sf.saxon.event.Receiver;
import net.sf.saxon.om.Axis;
import net.sf.saxon.om.AxisIterator;
import net.sf.saxon.om.DocumentInfo;
import net.sf.saxon.om.FastStringBuffer;
import net.sf.saxon.om.NamePool;
import net.sf.saxon.om.Navigator.AxisFilter;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.om.SiblingCountingNode;
import net.sf.saxon.om.VirtualNode;
import net.sf.saxon.pattern.NodeTest;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.Value;
/**
* This is a basic implementation of the Saxon NodeInfo and related interfaces.
* Most methods are trivial implementations which immediately throw
* {@link UnsupportedOperationException}. A few of the methods actually have
* useful implementations, such as {@link #iterateAxis(byte, NodeTest)} and
* {@link #isSameNodeInfo(NodeInfo)}.
*/
@Deprecated
@InternalApi
public class AbstractNodeInfo implements VirtualNode, SiblingCountingNode {
@Override
public String getSystemId() {
throw createUnsupportedOperationException("Source.getSystemId()");
}
@Override
public void setSystemId(String systemId) {
throw createUnsupportedOperationException("Source.setSystemId(String)");
}
@Override
public String getStringValue() {
throw createUnsupportedOperationException("ValueRepresentation.getStringValue()");
}
@Override
public CharSequence getStringValueCS() {
throw createUnsupportedOperationException("ValueRepresentation.getStringValueCS()");
}
@Override
public SequenceIterator getTypedValue() throws XPathException {
throw createUnsupportedOperationException("Item.getTypedValue()");
}
@Override
public Object getUnderlyingNode() {
throw createUnsupportedOperationException("VirtualNode.getUnderlyingNode()");
}
@Override
public int getSiblingPosition() {
throw createUnsupportedOperationException("SiblingCountingNode.getSiblingPosition()");
}
@Override
public Value atomize() throws XPathException {
throw createUnsupportedOperationException("NodeInfo.atomize()");
}
@Override
public int compareOrder(NodeInfo other) {
throw createUnsupportedOperationException("NodeInfo.compareOrder(NodeInfo)");
}
@Override
public void copy(Receiver receiver, int whichNamespaces, boolean copyAnnotations, int locationId)
throws XPathException {
throw createUnsupportedOperationException("ValueRepresentation.copy(Receiver, int, boolean, int)");
}
/**
* This implementation considers to NodeInfo objects to be equal, if their
* underlying nodes are equal.
*
* {@inheritDoc}
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other instanceof ElementNode) {
return this.getUnderlyingNode() == ((ElementNode) other).getUnderlyingNode();
}
return false;
}
@Override
public int hashCode() {
if (this.getUnderlyingNode() != null) {
return super.hashCode() + 31 * this.getUnderlyingNode().hashCode();
} else {
return super.hashCode();
}
}
@Override
public void generateId(FastStringBuffer buffer) {
throw createUnsupportedOperationException("NodeInfo.generateId(FastStringBuffer)");
}
@Override
public String getAttributeValue(int fingerprint) {
throw createUnsupportedOperationException("NodeInfo.getAttributeValue(int)");
}
@Override
public String getBaseURI() {
throw createUnsupportedOperationException("NodeInfo.getBaseURI()");
}
@Override
public int getColumnNumber() {
throw createUnsupportedOperationException("NodeInfo.getColumnNumber()");
}
@Override
public Configuration getConfiguration() {
throw createUnsupportedOperationException("NodeInfo.getConfiguration()");
}
@Override
public int[] getDeclaredNamespaces(int[] buffer) {
throw createUnsupportedOperationException("NodeInfo.getDeclaredNamespaces(int[])");
}
@Override
public String getDisplayName() {
throw createUnsupportedOperationException("NodeInfo.getDisplayName()");
}
/**
* This implementation always returns 0.
*
* {@inheritDoc}
*/
@Override
public int getDocumentNumber() {
return 0;
}
@Override
public DocumentInfo getDocumentRoot() {
throw createUnsupportedOperationException("NodeInfo.getDocumentRoot()");
}
@Override
public int getFingerprint() {
throw createUnsupportedOperationException("NodeInfo.getFingerprint()");
}
@Override
public int getLineNumber() {
throw createUnsupportedOperationException("NodeInfo.getLineNumber()");
}
@Override
public String getLocalPart() {
throw createUnsupportedOperationException("NodeInfo.getLocalPart()");
}
@Override
public int getNameCode() {
throw createUnsupportedOperationException("NodeInfo.getNameCode()");
}
@Override
public NamePool getNamePool() {
throw createUnsupportedOperationException("NodeInfo.getNamePool()");
}
@Override
public int getNodeKind() {
throw createUnsupportedOperationException("NodeInfo.getNodeKind()");
}
@Override
public NodeInfo getParent() {
throw createUnsupportedOperationException("NodeInfo.getParent()");
}
@Override
public String getPrefix() {
throw createUnsupportedOperationException("NodeInfo.getPrefix()");
}
@Override
public NodeInfo getRoot() {
throw createUnsupportedOperationException("NodeInfo.getRoot()");
}
@Override
public int getTypeAnnotation() {
throw createUnsupportedOperationException("NodeInfo.getTypeAnnotation()");
}
@Override
public String getURI() {
throw createUnsupportedOperationException("NodeInfo.getURI()");
}
@Override
public boolean hasChildNodes() {
throw createUnsupportedOperationException("NodeInfo.hasChildNodes()");
}
@Override
public boolean isId() {
throw createUnsupportedOperationException("NodeInfo.isId()");
}
@Override
public boolean isIdref() {
throw createUnsupportedOperationException("NodeInfo.isIdref()");
}
@Override
public boolean isNilled() {
throw createUnsupportedOperationException("NodeInfo.isNilled()");
}
/**
* This implementation delegates to {@link #equals(Object)}, per the Saxon
* documentation's description of this method's behavior.
*
* {@inheritDoc}
*/
@Override
public boolean isSameNodeInfo(NodeInfo other) {
return this.equals(other);
}
@Override
public AxisIterator iterateAxis(byte axisNumber) {
throw createUnsupportedOperationException(
"NodeInfo.iterateAxis(byte) for axis '" + Axis.axisName[axisNumber] + "'");
}
/**
* This implementation calls {@link #iterateAxis(byte)} to get an
* {@link AxisIterator} which is then optionally filtered using
* {@link AxisFilter}.
*
* {@inheritDoc}
*/
@Override
public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
return filter(iterateAxis(axisNumber), nodeTest);
}
protected static AxisIterator filter(AxisIterator axisIterator, NodeTest nodeTest) {
return nodeTest != null ? new AxisFilter(axisIterator, nodeTest) : axisIterator;
}
/**
* Used to create a customized instance of UnsupportedOperationException.
* The caller of this method is intended to <code>throw</code> the
* exception.
*
* @param name
* Method name that is not supported.
* @return A UnsupportedOperationException indicated the method is not
* supported by the implementation class.
*/
protected UnsupportedOperationException createUnsupportedOperationException(String name) {
return new UnsupportedOperationException(name + " is not implemented by " + this.getClass().getName());
}
}

View File

@ -1,50 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.saxon;
import java.util.Iterator;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sf.saxon.om.Navigator;
import net.sf.saxon.om.SequenceIterator;
/**
* An adapter over our {@link net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator}
* for the Saxon model.
*/
@Deprecated
@InternalApi
public class AttributeAxisIterator extends Navigator.BaseEnumeration {
protected final ElementNode startNodeInfo;
protected final Iterator<Attribute> iterator;
/**
* Create an iterator over the Attribute axis for the given ElementNode.
*
* @see net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator
*/
public AttributeAxisIterator(ElementNode startNodeInfo) {
this.startNodeInfo = startNodeInfo;
this.iterator = startNodeInfo.node.getXPathAttributesIterator();
}
@Override
public SequenceIterator getAnother() {
return new AttributeAxisIterator(startNodeInfo);
}
@Override
public void advance() {
if (this.iterator.hasNext()) {
Attribute attribute = this.iterator.next();
super.current = new AttributeNode(startNodeInfo, attribute, super.position());
} else {
super.current = null;
}
}
}

View File

@ -1,85 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.saxon;
import java.util.List;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger;
import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
import net.sf.saxon.value.Value;
/**
* A Saxon OM Attribute node for an AST Node Attribute.
* Belongs to an {@link ElementNode}, and wraps an
* {@link Attribute}.
*/
@Deprecated
@InternalApi
public class AttributeNode extends BaseNodeInfo {
protected final Attribute attribute;
protected final int id;
protected Value value;
/**
* Creates a new AttributeNode from a PMD Attribute.
*
* @param parent Parent elemtn
* @param id The index within the attribute order
*/
public AttributeNode(ElementNode parent, Attribute attribute, int id) {
super(Type.ATTRIBUTE, parent.getNamePool(), attribute.getName(), parent);
this.attribute = attribute;
this.id = id;
}
@Override
public String getLocalPart() {
return attribute.getName();
}
private DeprecatedAttrLogger getAttrCtx() {
return parent == null ? DeprecatedAttrLogger.noop()
: parent.document.getAttrCtx();
}
@Override
public Value atomize() {
getAttrCtx().recordUsageOf(attribute);
if (value == null) {
Object data = attribute.getValue();
if (data instanceof List) {
value = SaxonXPathRuleQuery.getSequenceRepresentation((List<?>) data);
} else {
value = SaxonXPathRuleQuery.getAtomicRepresentation(attribute.getValue());
}
}
return value;
}
@Override
public CharSequence getStringValueCS() {
return attribute.getStringValue();
}
@Override
public SequenceIterator getTypedValue() throws XPathException {
return atomize().iterate();
}
@Override
public int compareOrder(NodeInfo other) {
return Integer.signum(this.id - ((AttributeNode) other).id);
}
}

View File

@ -1,76 +0,0 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.saxon;
import net.sf.saxon.om.FingerprintedNode;
import net.sf.saxon.om.NamePool;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.SiblingCountingNode;
import net.sf.saxon.om.VirtualNode;
abstract class BaseNodeInfo extends AbstractNodeInfo implements VirtualNode, SiblingCountingNode, FingerprintedNode {
// It's important that all our NodeInfo implementations share the
// same getNodeKind implementation, otherwise NameTest spends a lot
// of time in virtual dispatch
private final int nodeKind;
private final NamePool namePool;
private final int fingerprint;
protected final ElementNode parent;
BaseNodeInfo(int nodeKind, NamePool namePool, String localName, ElementNode parent) {
this.nodeKind = nodeKind;
this.namePool = namePool;
this.fingerprint = namePool.allocate("", "", localName) & NamePool.FP_MASK;
this.parent = parent;
}
@Override
public final String getURI() {
return "";
}
@Override
public final String getBaseURI() {
return "";
}
@Override
public String getPrefix() {
return "";
}
@Override
public final NodeInfo getParent() {
return parent;
}
@Override
public int getNameCode() {
// note: the nameCode is only equal to the fingerprint because
// this implementation does not use namespace prefixes
// if we change that (eg for embedded language support) then
// we'll need to worry about this. See NamePool.FP_MASK
return fingerprint;
}
@Override
public final int getFingerprint() {
return fingerprint;
}
@Override
public final NamePool getNamePool() {
return namePool;
}
@Override
public final int getNodeKind() {
return nodeKind;
}
}

View File

@ -1,109 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.saxon;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger;
import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery;
import net.sf.saxon.om.Axis;
import net.sf.saxon.om.AxisIterator;
import net.sf.saxon.om.DocumentInfo;
import net.sf.saxon.om.NamePool;
import net.sf.saxon.om.Navigator;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.SingleNodeIterator;
import net.sf.saxon.type.Type;
/**
* A Saxon OM Document node for an AST Node.
*/
@Deprecated
@InternalApi
public class DocumentNode extends BaseNodeInfo implements DocumentInfo {
/**
* The root ElementNode of the DocumentNode.
*/
protected final ElementNode rootNode;
/**
* Mapping from AST Node to corresponding ElementNode.
*/
public final Map<Node, ElementNode> nodeToElementNode = new HashMap<>();
private DeprecatedAttrLogger attrCtx;
/**
* Construct a DocumentNode, with the given AST Node serving as the root
* ElementNode.
*
* @param node The root AST Node.
* @param namePool Pool to share names
*
* @see ElementNode
*/
public DocumentNode(Node node, NamePool namePool) {
super(Type.DOCUMENT, namePool, "", null);
this.rootNode = new ElementNode(this, new IdGenerator(), null, node, -1, namePool);
}
@Deprecated
public DocumentNode(Node node) {
this(node, SaxonXPathRuleQuery.getNamePool());
}
@Override
public String[] getUnparsedEntity(String name) {
throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntity(String)");
}
@Override
public Iterator getUnparsedEntityNames() {
throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntityNames()");
}
@Override
public NodeInfo selectID(String id) {
throw createUnsupportedOperationException("DocumentInfo.selectID(String)");
}
@Override
public DocumentInfo getDocumentRoot() {
return this;
}
@Override
public boolean hasChildNodes() {
return true;
}
@Override
public AxisIterator iterateAxis(byte axisNumber) {
switch (axisNumber) {
case Axis.DESCENDANT:
return new Navigator.DescendantEnumeration(this, false, true);
case Axis.DESCENDANT_OR_SELF:
return new Navigator.DescendantEnumeration(this, true, true);
case Axis.CHILD:
return SingleNodeIterator.makeIterator(rootNode);
default:
return super.iterateAxis(axisNumber);
}
}
public DeprecatedAttrLogger getAttrCtx() {
return attrCtx == null ? DeprecatedAttrLogger.noop() : attrCtx;
}
public void setAttrCtx(DeprecatedAttrLogger attrCtx) {
this.attrCtx = attrCtx;
}
}

View File

@ -1,267 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.saxon;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery;
import net.sf.saxon.om.Axis;
import net.sf.saxon.om.AxisIterator;
import net.sf.saxon.om.DocumentInfo;
import net.sf.saxon.om.EmptyIterator;
import net.sf.saxon.om.NamePool;
import net.sf.saxon.om.Navigator;
import net.sf.saxon.om.Navigator.BaseEnumeration;
import net.sf.saxon.om.NodeArrayIterator;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.om.SingleNodeIterator;
import net.sf.saxon.om.SingletonIterator;
import net.sf.saxon.pattern.NameTest;
import net.sf.saxon.pattern.NodeTest;
import net.sf.saxon.type.Type;
import net.sf.saxon.value.AtomicValue;
import net.sf.saxon.value.StringValue;
import net.sf.saxon.value.UntypedAtomicValue;
import net.sf.saxon.value.Value;
/**
* A Saxon OM Element type node for an AST Node.
*/
@Deprecated
@InternalApi
public class ElementNode extends BaseNodeInfo {
protected final DocumentNode document;
protected final ElementNode parent;
protected final Node node;
protected final int id;
protected final int siblingPosition;
protected final NodeInfo[] children;
private Map<Integer, AttributeNode> attributes;
@Deprecated
public ElementNode(DocumentNode document, IdGenerator idGenerator, ElementNode parent, Node node, int siblingPosition) {
this(document, idGenerator, parent, node, siblingPosition, SaxonXPathRuleQuery.getNamePool());
}
public ElementNode(DocumentNode document,
IdGenerator idGenerator,
ElementNode parent,
Node node,
int siblingPosition,
NamePool namePool) {
super(Type.ELEMENT, namePool, node.getXPathNodeName(), parent);
this.document = document;
this.parent = parent;
this.node = node;
this.id = idGenerator.getNextId();
this.siblingPosition = siblingPosition;
if (node.getNumChildren() > 0) {
this.children = new NodeInfo[node.getNumChildren()];
for (int i = 0; i < children.length; i++) {
children[i] = new ElementNode(document, idGenerator, this, node.getChild(i), i, namePool);
}
} else {
this.children = null;
}
document.nodeToElementNode.put(node, this);
}
private Map<Integer, AttributeNode> getAttributes() {
if (attributes == null) {
attributes = new HashMap<>();
Iterator<Attribute> iter = node.getXPathAttributesIterator();
int idx = 0;
while (iter.hasNext()) {
Attribute next = iter.next();
AttributeNode attrNode = new AttributeNode(this, next, idx++);
attributes.put(attrNode.getFingerprint(), attrNode);
}
}
return attributes;
}
@Override
public Object getUnderlyingNode() {
return node;
}
@Override
public int getSiblingPosition() {
return siblingPosition;
}
@Override
public int getColumnNumber() {
return node.getBeginColumn();
}
@Override
public int getLineNumber() {
return node.getBeginLine();
}
@Override
public boolean hasChildNodes() {
return children != null;
}
@Override
public DocumentInfo getDocumentRoot() {
return document;
}
@Override
public String getLocalPart() {
return node.getXPathNodeName();
}
@Override
public SequenceIterator getTypedValue() {
return SingletonIterator.makeIterator((AtomicValue) atomize());
}
@Override
public Value atomize() {
switch (getNodeKind()) {
case Type.COMMENT:
case Type.PROCESSING_INSTRUCTION:
return new StringValue(getStringValueCS());
default:
return new UntypedAtomicValue(getStringValueCS());
}
}
@Override
public CharSequence getStringValueCS() {
return "";
}
@Override
public int compareOrder(NodeInfo other) {
int result;
if (this.isSameNodeInfo(other)) {
result = 0;
} else {
result = Integer.signum(this.getLineNumber() - other.getLineNumber());
if (result == 0) {
result = Integer.signum(this.getColumnNumber() - other.getColumnNumber());
}
if (result == 0) {
if (this.getParent().equals(other.getParent())) {
result = Integer.signum(this.getSiblingPosition() - ((ElementNode) other).getSiblingPosition());
} else {
// we must not return 0 here, otherwise the node might be removed as duplicate when creating
// a union set. The the nodes are definitively different nodes (isSameNodeInfo == false).
result = 1;
}
}
}
return result;
}
@Override
public String getDisplayName() {
return getLocalPart();
}
@Override
public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
if (axisNumber == Axis.ATTRIBUTE) {
if (nodeTest instanceof NameTest) {
if ((nodeTest.getNodeKindMask() & (1 << Type.ATTRIBUTE)) == 0) {
return EmptyIterator.getInstance();
} else {
int fp = nodeTest.getFingerprint();
if (fp != -1) {
return SingleNodeIterator.makeIterator(getAttributes().get(fp));
}
}
}
}
return super.iterateAxis(axisNumber, nodeTest);
}
@SuppressWarnings("PMD.MissingBreakInSwitch")
@Override
public AxisIterator iterateAxis(final byte axisNumber) {
switch (axisNumber) {
case Axis.ANCESTOR:
return new Navigator.AncestorEnumeration(this, false);
case Axis.ANCESTOR_OR_SELF:
return new Navigator.AncestorEnumeration(this, true);
case Axis.ATTRIBUTE:
return new AttributeEnumeration();
case Axis.CHILD:
if (children == null) {
return EmptyIterator.getInstance();
} else {
return new NodeArrayIterator(children);
}
case Axis.DESCENDANT:
return new Navigator.DescendantEnumeration(this, false, true);
case Axis.DESCENDANT_OR_SELF:
return new Navigator.DescendantEnumeration(this, true, true);
case Axis.FOLLOWING:
return new Navigator.FollowingEnumeration(this);
case Axis.FOLLOWING_SIBLING:
if (parent == null || siblingPosition == parent.children.length - 1) {
return EmptyIterator.getInstance();
} else {
return new NodeArrayIterator(parent.children, siblingPosition + 1, parent.children.length);
}
case Axis.NAMESPACE:
return super.iterateAxis(axisNumber);
case Axis.PARENT:
return SingleNodeIterator.makeIterator(parent);
case Axis.PRECEDING:
return new Navigator.PrecedingEnumeration(this, false);
case Axis.PRECEDING_SIBLING:
if (parent == null || siblingPosition == 0) {
return EmptyIterator.getInstance();
} else {
return new NodeArrayIterator(parent.children, 0, siblingPosition);
}
case Axis.SELF:
return SingleNodeIterator.makeIterator(this);
case Axis.PRECEDING_OR_ANCESTOR:
return new Navigator.PrecedingEnumeration(this, true);
default:
return super.iterateAxis(axisNumber);
}
}
private class AttributeEnumeration extends BaseEnumeration {
private final Iterator<AttributeNode> iter = getAttributes().values().iterator();
@Override
public void advance() {
if (iter.hasNext()) {
current = iter.next();
} else {
current = null;
}
}
@Override
public SequenceIterator getAnother() {
return new AttributeEnumeration();
}
}
}

View File

@ -4,10 +4,6 @@
package net.sourceforge.pmd.lang.rule;
import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0;
import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0_COMPATIBILITY;
import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_2_0;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -21,13 +17,12 @@ import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.ast.AstProcessingStage;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger;
import net.sourceforge.pmd.lang.rule.xpath.JaxenXPathRuleQuery;
import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery;
import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery;
import net.sourceforge.pmd.lang.rule.xpath.XPathVersion;
import net.sourceforge.pmd.properties.EnumeratedProperty;
import net.sourceforge.pmd.properties.StringProperty;
/**
* Rule that tries to match an XPath expression against a DOM view of an AST.
*/
@ -43,33 +38,22 @@ public class XPathRule extends AbstractRule {
.uiOrder(1.0f)
.build();
private static final Map<String, String> XPATH_VERSIONS;
static {
Map<String, String> tmp = new HashMap<>();
tmp.put(XPATH_1_0, XPATH_1_0);
tmp.put(XPATH_1_0_COMPATIBILITY, XPATH_1_0_COMPATIBILITY);
tmp.put(XPATH_2_0, XPATH_2_0);
XPATH_VERSIONS = Collections.unmodifiableMap(tmp);
}
/**
* @deprecated Use {@link #XPathRule(XPathVersion, String)}
*/
@Deprecated
public static final EnumeratedProperty<String> VERSION_DESCRIPTOR = EnumeratedProperty.<String>named("version")
.desc("XPath specification version")
.mappings(XPATH_VERSIONS)
.defaultValue(XPATH_1_0)
.type(String.class)
.mappings(getXPathVersions())
.defaultValue(XPathVersion.XPATH_2_0)
.type(XPathVersion.class)
.uiOrder(2.0f)
.build();
/**
* This is initialized only once when calling {@link #evaluate(Node, RuleContext)} or {@link #getRuleChainVisits()}.
*/
private XPathRuleQuery xpathRuleQuery;
private SaxonXPathRuleQuery xpathRuleQuery;
// this is shared with rules forked by deepCopy, used by the XPathRuleQuery
private DeprecatedAttrLogger attrLogger = DeprecatedAttrLogger.create(this);
@ -84,6 +68,7 @@ public class XPathRule extends AbstractRule {
definePropertyDescriptor(VERSION_DESCRIPTOR);
}
/**
* Creates a new XPathRule and associates the XPath query.
*
@ -94,6 +79,7 @@ public class XPathRule extends AbstractRule {
setXPath(xPath);
}
/**
* Make a new XPath rule with the given version + expression
*
@ -148,9 +134,10 @@ public class XPathRule extends AbstractRule {
*/
@Deprecated
public void setVersion(final String version) {
setProperty(XPathRule.VERSION_DESCRIPTOR, version);
setProperty(XPathRule.VERSION_DESCRIPTOR, XPathVersion.fromString(version));
}
@Override
public void apply(List<? extends Node> nodes, RuleContext ctx) {
for (Node node : nodes) {
@ -158,6 +145,7 @@ public class XPathRule extends AbstractRule {
}
}
/**
* Evaluate the XPath query with the AST node. All matches are reported as violations.
*
@ -178,6 +166,7 @@ public class XPathRule extends AbstractRule {
}
}
/**
* Initializes {@link #xpathRuleQuery} iff {@link #xPathRuleQueryNeedsInitialization()} is true. To select the
* engine in which the query will be run it looks at the XPath version.
@ -190,17 +179,14 @@ public class XPathRule extends AbstractRule {
throw new IllegalStateException("Invalid XPath version, should have been caught by Rule::dysfunctionReason");
}
if (version == XPathVersion.XPATH_1_0) {
xpathRuleQuery = new JaxenXPathRuleQuery(attrLogger);
} else {
xpathRuleQuery = new SaxonXPathRuleQuery(attrLogger);
}
xpathRuleQuery.setXPath(xpath);
xpathRuleQuery.setVersion(version.getXmlName());
xpathRuleQuery.setProperties(getPropertiesByPropertyDescriptor());
xpathRuleQuery = new SaxonXPathRuleQuery(xpath,
version,
getPropertiesByPropertyDescriptor(),
getLanguage().getDefaultVersion().getLanguageVersionHandler().getXPathHandler(),
attrLogger);
}
/**
* Checks if the {@link #xpathRuleQuery} is null and therefore requires initialization.
*
@ -222,6 +208,7 @@ public class XPathRule extends AbstractRule {
return super.getRuleChainVisits();
}
@Override
public String dysfunctionReason() {
if (getVersion() == null) {
@ -232,10 +219,17 @@ public class XPathRule extends AbstractRule {
return null;
}
@Override
public boolean dependsOn(AstProcessingStage<?> stage) {
// FIXME must be made language-specific
return true;
}
private static Map<String, String> getXPathVersions() {
Map<String, String> tmp = new HashMap<>();
for (XPathVersion v : XPathVersion.values()) {
tmp.put(v.getXmlName(), v.getXmlName());
}
return Collections.unmodifiableMap(tmp);
}
}

View File

@ -1,82 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.rule.xpath;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.properties.PropertyDescriptor;
/**
* This implementation of XPathRuleQuery provides support for RuleChain visits.
*
* @deprecated Internal API
*/
@Deprecated
@InternalApi
public abstract class AbstractXPathRuleQuery implements XPathRuleQuery {
/**
* The XPath query string.
*/
protected String xpath;
/**
* The XPath version;
*/
protected String version;
/**
* The properties.
*/
protected Map<PropertyDescriptor<?>, Object> properties;
/**
* Subclasses can manage RuleChain visits via this list.
*/
protected final List<String> ruleChainVisits = new ArrayList<>();
@Override
public void setXPath(final String xpath) {
this.xpath = xpath;
}
@Override
public void setVersion(String version) throws UnsupportedOperationException {
if (!isSupportedVersion(version)) {
throw new UnsupportedOperationException(
this.getClass().getSimpleName() + " does not support XPath version: " + version);
}
this.version = version;
}
/**
* Subclasses should implement to indicate whether an XPath version is
* supported.
*
* @param version
* The XPath version.
* @return <code>true</code> if the XPath version is supported,
* <code>false</code> otherwise.
*/
protected abstract boolean isSupportedVersion(String version);
@Override
public void setProperties(Map<PropertyDescriptor<?>, Object> properties) {
this.properties = properties;
}
@Override
public List<String> getRuleChainVisits() {
return ruleChainVisits;
}
@Override
public abstract List<Node> evaluate(Node node, RuleContext data);
}

View File

@ -1,282 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.rule.xpath;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jaxen.BaseXPath;
import org.jaxen.JaxenException;
import org.jaxen.Navigator;
import org.jaxen.SimpleVariableContext;
import org.jaxen.XPath;
import org.jaxen.expr.AllNodeStep;
import org.jaxen.expr.DefaultXPathFactory;
import org.jaxen.expr.Expr;
import org.jaxen.expr.LocationPath;
import org.jaxen.expr.NameStep;
import org.jaxen.expr.Predicate;
import org.jaxen.expr.Step;
import org.jaxen.expr.UnionExpr;
import org.jaxen.expr.XPathFactory;
import org.jaxen.saxpath.Axis;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.internal.ContextualizedNavigator;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger;
import net.sourceforge.pmd.properties.PropertyDescriptor;
/**
* This is a Jaxen based XPathRule query.
*
* @deprecated Internal API
*/
@Deprecated
@InternalApi
public class JaxenXPathRuleQuery extends AbstractXPathRuleQuery {
private static final Logger LOG = Logger.getLogger(JaxenXPathRuleQuery.class.getName());
static final String AST_ROOT = "_AST_ROOT_";
private InitializationStatus initializationStatus = InitializationStatus.NONE;
// Mapping from Node name to applicable XPath queries
Map<String, List<XPath>> nodeNameToXPaths;
private final DeprecatedAttrLogger attrCtx;
public JaxenXPathRuleQuery() {
this(DeprecatedAttrLogger.noop());
}
public JaxenXPathRuleQuery(DeprecatedAttrLogger attrCtx) {
this.attrCtx = attrCtx;
}
@Override
public boolean isSupportedVersion(String version) {
return XPATH_1_0.equals(version);
}
@Override
public List<Node> evaluate(final Node node, final RuleContext data) {
final List<Node> results = new ArrayList<>();
try {
initializeExpressionIfStatusIsNoneOrPartial(new ContextualizedNavigator(attrCtx));
List<XPath> xPaths = getXPathsForNodeOrDefault(node.getXPathNodeName());
for (XPath xpath : xPaths) {
@SuppressWarnings("unchecked")
final List<Node> matchedNodes = xpath.selectNodes(node);
results.addAll(matchedNodes);
}
} catch (final JaxenException e) {
throw new RuntimeException(e);
}
return results;
}
/**
* Get the XPath queries associated with the node name. If there are none, the XPath queries for the {@link #AST_ROOT}
* are obtained.
*
* @param nodeName the id of the node
* @return the list of XPath queries that match the node name
*/
private List<XPath> getXPathsForNodeOrDefault(final String nodeName) {
List<XPath> xPaths = nodeNameToXPaths.get(nodeName);
if (xPaths == null) {
xPaths = nodeNameToXPaths.get(AST_ROOT);
}
return xPaths;
}
@Override
public List<String> getRuleChainVisits() {
try {
// No Navigator available in this context
initializeExpressionIfStatusIsNoneOrPartial(null);
return super.getRuleChainVisits();
} catch (final JaxenException ex) {
throw new RuntimeException(ex);
}
}
/**
*
* @param navigator the navigator which is required to be non-null if the {@link #initializationStatus} is PARTIAL.
* @throws JaxenException
*/
@SuppressWarnings("unchecked")
private void initializeExpressionIfStatusIsNoneOrPartial(final Navigator navigator) throws JaxenException {
if (initializationStatus == InitializationStatus.FULL) {
return;
}
if (initializationStatus == InitializationStatus.PARTIAL && navigator == null) {
LOG.severe("XPathRule is not initialized because no navigator was provided. "
+ "Please make sure to implement getXPathHandler in the handler of the language. "
+ "See also AbstractLanguageVersionHandler.");
return;
}
initializeXPathExpression(navigator);
}
private void initializeXPathExpression(final Navigator navigator) throws JaxenException {
/*
Attempt to use the RuleChain with this XPath query.
To do so, the queries should generally look like //TypeA or //TypeA | //TypeB. We will look at the parsed XPath
AST using the Jaxen APIs to make this determination.
If the query is not exactly what we are looking for, do not use the
RuleChain.
*/
nodeNameToXPaths = new HashMap<>();
final BaseXPath originalXPath = createXPath(xpath, navigator);
addQueryToNode(originalXPath, AST_ROOT);
boolean useRuleChain = true;
final Deque<Expr> pending = new ArrayDeque<>();
pending.push(originalXPath.getRootExpr());
while (!pending.isEmpty()) {
final Expr node = pending.pop();
// Need to prove we can handle this part of the query
boolean valid = false;
// Must be a LocationPath... that is something like //Type
if (node instanceof LocationPath) {
final LocationPath locationPath = (LocationPath) node;
if (locationPath.isAbsolute()) {
// Should be at least two steps
@SuppressWarnings("unchecked")
final List<Step> steps = locationPath.getSteps();
if (steps.size() >= 2) {
final Step step1 = steps.get(0);
final Step step2 = steps.get(1);
// First step should be an AllNodeStep using the
// descendant or self axis
if (step1 instanceof AllNodeStep
&& step1.getAxis() == Axis.DESCENDANT_OR_SELF) {
// Second step should be a NameStep using the child
// axis.
if (step2 instanceof NameStep && step2.getAxis() == Axis.CHILD) {
// Construct a new expression that is
// appropriate for RuleChain use
final XPathFactory xpathFactory = new DefaultXPathFactory();
// Instead of an absolute location path, we'll
// be using a relative path
final LocationPath relativeLocationPath = xpathFactory.createRelativeLocationPath();
// The first step will be along the self axis
final Step allNodeStep = xpathFactory.createAllNodeStep(Axis.SELF);
// Retain all predicates from the original name
// step
@SuppressWarnings("unchecked")
final List<Predicate> predicates = step2.getPredicates();
for (Predicate predicate : predicates) {
allNodeStep.addPredicate(predicate);
}
relativeLocationPath.addStep(allNodeStep);
// Retain the remaining steps from the original
// location path
for (int i = 2; i < steps.size(); i++) {
relativeLocationPath.addStep(steps.get(i));
}
final BaseXPath xpath = createXPath(relativeLocationPath.getText(), navigator);
addQueryToNode(xpath, ((NameStep) step2).getLocalName());
valid = true;
}
}
}
}
} else if (node instanceof UnionExpr) { // Or a UnionExpr, that is
// something like //TypeA |
// //TypeB
UnionExpr unionExpr = (UnionExpr) node;
pending.push(unionExpr.getLHS());
pending.push(unionExpr.getRHS());
valid = true;
}
if (!valid) {
useRuleChain = false;
break;
}
}
if (useRuleChain) {
// Use the RuleChain for all the nodes extracted from the xpath
// queries
super.ruleChainVisits.addAll(nodeNameToXPaths.keySet());
} else {
// Use original XPath if we cannot use the RuleChain
nodeNameToXPaths.clear();
addQueryToNode(originalXPath, AST_ROOT);
if (LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, "Unable to use RuleChain for XPath: " + xpath);
}
}
if (navigator == null) {
this.initializationStatus = InitializationStatus.PARTIAL;
// Clear the node data, because we did not have a Navigator
nodeNameToXPaths = null;
} else {
this.initializationStatus = InitializationStatus.FULL;
}
}
/**
* Relates an XPath query to a node by adding the query to the {@link #nodeNameToXPaths}.
*
* @param xPath the query to do over a node
* @param nodeName the node on which to do the query
*/
private void addQueryToNode(final XPath xPath, final String nodeName) {
List<XPath> xPathsForNode = nodeNameToXPaths.get(nodeName);
if (xPathsForNode == null) {
xPathsForNode = new ArrayList<>();
nodeNameToXPaths.put(nodeName, xPathsForNode);
}
xPathsForNode.add(xPath);
}
private BaseXPath createXPath(final String xpathQueryString, final Navigator navigator) throws JaxenException {
final BaseXPath xpath = new BaseXPath(xpathQueryString, navigator);
if (properties.size() > 1) {
final SimpleVariableContext vc = new SimpleVariableContext();
for (Entry<PropertyDescriptor<?>, Object> e : properties.entrySet()) {
final String propName = e.getKey().name();
if (!"xpath".equals(propName)) {
final Object value = e.getValue();
vc.setVariableValue(propName, value != null ? value.toString() : null);
}
}
xpath.setVariableContext(vc);
}
return xpath;
}
private enum InitializationStatus {
NONE, PARTIAL, FULL
}
}

View File

@ -1,70 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.xpath;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.LanguageVersionHandler;
import net.sf.saxon.sxpath.IndependentContext;
/**
* This class serves as the means to perform XPath related static
* initialization. For example, initializing custom Jaxen Functions.
* Initialization should be performed before any XPath related operations are
* performed.
*
* @deprecated Is internal API
*/
@InternalApi
@Deprecated
public final class Initializer {
private Initializer() { }
/**
* Perform all initialization.
*/
public static void initialize() {
// noop as initialization is done in static block below
}
/**
* Perform all initialization.
*/
public static void initialize(IndependentContext context) {
context.declareNamespace("pmd", "java:" + PMDFunctions.class.getName());
for (Language language : LanguageRegistry.getLanguages()) {
for (LanguageVersion languageVersion : language.getVersions()) {
LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler();
if (languageVersionHandler != null) {
languageVersionHandler.getXPathHandler().initialize(context);
}
}
}
}
static {
initializeGlobal();
initializeLanguages();
}
private static void initializeGlobal() {
MatchesFunction.registerSelfInSimpleContext();
}
private static void initializeLanguages() {
for (Language language : LanguageRegistry.getLanguages()) {
for (LanguageVersion languageVersion : language.getVersions()) {
LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler();
if (languageVersionHandler != null) {
languageVersionHandler.getXPathHandler().initialize();
}
}
}
}
}

View File

@ -22,6 +22,6 @@ public class CPDCommandLineInterfaceTest {
System.setProperty(CPDCommandLineInterface.NO_EXIT_AFTER_RUN, "true");
CPDCommandLineInterface.main(new String[] { "--minimum-tokens", "340", "--language", "java", "--files",
"src/test/resources/net/sourceforge/pmd/cpd/files/", "--format", "xml", });
Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" + "<pmd-cpd/>", log.getLog());
Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" + "<pmd-cpd/>", log.getLog().trim());
}
}

View File

@ -1,144 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.rule.xpath;
import java.util.Collections;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.properties.PropertyDescriptor;
public class JaxenXPathRuleQueryTest {
@Test
public void testListAttribute() {
DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1);
assertQuery(1, "//dummyNode[@SimpleAtt = \"foo\"]", dummy);
assertQuery(1, "//dummyNode[@Enum = \"FOO\"]", dummy);
assertQuery(0, "//dummyNode[@Enum = \"BAR\"]", dummy);
// queries with lists are not supported with xpath 1.0
assertQuery(0, "//dummyNode[@List = \"[A, B]\"]", dummy);
assertQuery(0, "//dummyNode[contains(@List, \"B\")]", dummy);
assertQuery(0, "//dummyNode[@List = \"C\"]", dummy);
assertQuery(0, "//dummyNode[@EnumList = \"[FOO, BAR]\"]", dummy);
assertQuery(0, "//dummyNode[contains(@EnumList, \"BAR\")]", dummy);
assertQuery(0, "//dummyNode[@EmptyList = \"A\"]", dummy);
}
@Test
public void ruleChainVisits() {
final String xpath = "//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = 'false'] | //dummyNode";
JaxenXPathRuleQuery query = createQuery(xpath);
List<String> ruleChainVisits = query.getRuleChainVisits();
Assert.assertEquals(3, ruleChainVisits.size());
Assert.assertTrue(ruleChainVisits.contains("dummyNode"));
Assert.assertTrue(ruleChainVisits.contains("bar"));
// Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't
// match a real node name.
Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT));
DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1);
RuleContext data = new RuleContext();
data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion());
query.evaluate(dummy, data);
// note: the actual xpath queries are only available after evaluating
Assert.assertEquals(3, query.nodeNameToXPaths.size());
Assert.assertEquals("self::node()", query.nodeNameToXPaths.get("dummyNode").get(0).toString());
Assert.assertEquals("self::node()[(attribute::Public = \"false\")]", query.nodeNameToXPaths.get("dummyNode").get(1).toString());
Assert.assertEquals("self::node()[(attribute::Image = \"baz\")]/child::foo", query.nodeNameToXPaths.get("dummyNode").get(2).toString());
Assert.assertEquals("self::node()[(attribute::Public = \"true\")]", query.nodeNameToXPaths.get("bar").get(0).toString());
Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString());
}
@Test
public void ruleChainVisitsMultipleFilters() {
final String xpath = "//dummyNode[@Test1 = 'false'][@Test2 = 'true']";
JaxenXPathRuleQuery query = createQuery(xpath);
List<String> ruleChainVisits = query.getRuleChainVisits();
Assert.assertEquals(2, ruleChainVisits.size());
Assert.assertTrue(ruleChainVisits.contains("dummyNode"));
// Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't
// match a real node name.
Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT));
DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1);
RuleContext data = new RuleContext();
data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion());
query.evaluate(dummy, data);
// note: the actual xpath queries are only available after evaluating
Assert.assertEquals(2, query.nodeNameToXPaths.size());
Assert.assertEquals("self::node()[(attribute::Test1 = \"false\")][(attribute::Test2 = \"true\")]", query.nodeNameToXPaths.get("dummyNode").get(0).toString());
Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString());
}
@Test
public void ruleChainVisitsNested() {
final String xpath = "//dummyNode/foo/*/bar[@Test = 'false']";
JaxenXPathRuleQuery query = createQuery(xpath);
List<String> ruleChainVisits = query.getRuleChainVisits();
Assert.assertEquals(2, ruleChainVisits.size());
Assert.assertTrue(ruleChainVisits.contains("dummyNode"));
// Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't
// match a real node name.
Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT));
DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1);
RuleContext data = new RuleContext();
data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion());
query.evaluate(dummy, data);
// note: the actual xpath queries are only available after evaluating
Assert.assertEquals(2, query.nodeNameToXPaths.size());
Assert.assertEquals("self::node()/child::foo/child::*/child::bar[(attribute::Test = \"false\")]", query.nodeNameToXPaths.get("dummyNode").get(0).toString());
Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString());
}
@Test
public void ruleChainVisitsNested2() {
final String xpath = "//dummyNode/foo[@Baz = 'a']/*/bar[@Test = 'false']";
JaxenXPathRuleQuery query = createQuery(xpath);
List<String> ruleChainVisits = query.getRuleChainVisits();
Assert.assertEquals(2, ruleChainVisits.size());
Assert.assertTrue(ruleChainVisits.contains("dummyNode"));
// Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't
// match a real node name.
Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT));
DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1);
RuleContext data = new RuleContext();
data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion());
query.evaluate(dummy, data);
// note: the actual xpath queries are only available after evaluating
Assert.assertEquals(2, query.nodeNameToXPaths.size());
Assert.assertEquals("self::node()/child::foo[(attribute::Baz = \"a\")]/child::*/child::bar[(attribute::Test = \"false\")]", query.nodeNameToXPaths.get("dummyNode").get(0).toString());
Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString());
}
private static void assertQuery(int resultSize, String xpath, Node node) {
JaxenXPathRuleQuery query = createQuery(xpath);
RuleContext data = new RuleContext();
data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion());
List<Node> result = query.evaluate(node, data);
Assert.assertEquals(resultSize, result.size());
}
private static JaxenXPathRuleQuery createQuery(String xpath) {
JaxenXPathRuleQuery query = new JaxenXPathRuleQuery();
query.setVersion("1.0");
query.setProperties(Collections.<PropertyDescriptor<?>, Object>emptyMap());
query.setXPath(xpath);
return query;
}
}

View File

@ -13,7 +13,9 @@ import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.XPathHandler;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.rule.XPathRule.XPathVersion;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
@ -158,22 +160,6 @@ public class SaxonXPathRuleQueryTest {
.replaceAll("\\$zz:zz-?\\d+", "\\$zz:zz000");
}
@Test
public void ruleChainVisitsCompatibilityMode() {
SaxonXPathRuleQuery query = createQuery("//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = 'false']");
query.setVersion(XPathRuleQuery.XPATH_1_0_COMPATIBILITY);
List<String> ruleChainVisits = query.getRuleChainVisits();
Assert.assertEquals(2, ruleChainVisits.size());
Assert.assertTrue(ruleChainVisits.contains("dummyNode"));
Assert.assertTrue(ruleChainVisits.contains("bar"));
Assert.assertEquals(3, query.nodeNameToXPaths.size());
assertExpression("((self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Image, xs:anyAtomicType)), ($qq:qq6519275 singleton eq \"baz\"))])/child::element(foo, xs:anyType))", query.nodeNameToXPaths.get("dummyNode").get(0));
assertExpression("(self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq1529060733 singleton eq \"false\"))])", query.nodeNameToXPaths.get("dummyNode").get(1));
assertExpression("(self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq1484171695 singleton eq \"true\"))])", query.nodeNameToXPaths.get("bar").get(0));
assertExpression("((DocumentSorter(((((/)/descendant::element(dummyNode, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Image, xs:anyAtomicType)), ($qq:qq692331943 singleton eq \"baz\"))])/child::element(foo, xs:anyType))) | (((/)/descendant::element(bar, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq2127036371 singleton eq \"true\"))])) | (((/)/descendant::element(dummyNode, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq1529060733 singleton eq \"false\"))]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0));
}
private static void assertQuery(int resultSize, String xpath, Node node) {
SaxonXPathRuleQuery query = createQuery(xpath);
List<Node> result = query.evaluate(node, new RuleContext());
@ -181,18 +167,18 @@ public class SaxonXPathRuleQueryTest {
}
private static SaxonXPathRuleQuery createQuery(String xpath, PropertyDescriptor<?> ...descriptors) {
SaxonXPathRuleQuery query = new SaxonXPathRuleQuery();
query.setVersion(XPathRuleQuery.XPATH_2_0);
Map<PropertyDescriptor<?>, Object> props = new HashMap<>();
if (descriptors != null) {
Map<PropertyDescriptor<?>, Object> props = new HashMap<PropertyDescriptor<?>, Object>();
for (PropertyDescriptor<?> prop : descriptors) {
props.put(prop, prop.defaultValue());
}
query.setProperties(props);
} else {
query.setProperties(Collections.<PropertyDescriptor<?>, Object>emptyMap());
}
query.setXPath(xpath);
return query;
return new SaxonXPathRuleQuery(
xpath,
XPathVersion.XPATH_2_0,
props,
XPathHandler.getHandlerForFunctionDefs()
);
}
}

View File

@ -8,9 +8,13 @@ import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.lang.ast.DummyNode;
import net.sourceforge.pmd.lang.ast.xpath.internal.AstDocument;
import net.sourceforge.pmd.lang.ast.xpath.saxon.DocumentNode;
import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode;
import net.sf.saxon.sxpath.XPathEvaluator;
import net.sf.saxon.sxpath.XPathStaticContext;
public class ElementNodeTest {
@Test
@ -23,7 +27,9 @@ public class ElementNodeTest {
node.jjtAddChild(foo1, 0);
node.jjtAddChild(foo2, 1);
DocumentNode document = new DocumentNode(node);
final XPathEvaluator xpathEvaluator = new XPathEvaluator();
AstDocument document = new AstDocument(node, xpathEvaluator.getConfiguration());
ElementNode elementFoo1 = document.nodeToElementNode.get(foo1);
ElementNode elementFoo2 = document.nodeToElementNode.get(foo2);

Some files were not shown because too many files have changed in this diff Show More