forked from phoedos/pmd
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:
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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)) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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++;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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
Reference in New Issue
Block a user