Merge branch 'pr-736'
This commit is contained in:
@ -6,8 +6,11 @@ package net.sourceforge.pmd.lang.ast.xpath;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
@ -98,17 +101,20 @@ public class AttributeAxisIterator implements Iterator<Attribute> {
|
||||
return new Attribute(node, m.name, m.method);
|
||||
}
|
||||
|
||||
private static final Set<Class<?>> CONSIDERED_RETURN_TYPES
|
||||
= new HashSet<>(Arrays.<Class<?>>asList(Integer.TYPE, Boolean.TYPE, Double.TYPE, String.class, Long.TYPE, Character.TYPE, Float.TYPE));
|
||||
|
||||
private static final Set<String> FILTERED_OUT_NAMES
|
||||
= new HashSet<>(Arrays.asList("toString", "getClass", "getTypeNameNode", "hashCode", "getImportedNameNode", "getScope"));
|
||||
|
||||
protected boolean isAttributeAccessor(Method method) {
|
||||
|
||||
String methodName = method.getName();
|
||||
boolean deprecated = method.getAnnotation(Deprecated.class) != null;
|
||||
|
||||
return !deprecated
|
||||
&& (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType()
|
||||
|| Double.TYPE == method.getReturnType() || String.class == method.getReturnType())
|
||||
&& method.getParameterTypes().length == 0 && Void.TYPE != method.getReturnType()
|
||||
&& !methodName.startsWith("jjt") && !"toString".equals(methodName) && !"getScope".equals(methodName)
|
||||
&& !"getClass".equals(methodName) && !"getTypeNameNode".equals(methodName)
|
||||
&& !"getImportedNameNode".equals(methodName) && !"hashCode".equals(methodName);
|
||||
&& CONSIDERED_RETURN_TYPES.contains(method.getReturnType())
|
||||
&& method.getParameterTypes().length == 0
|
||||
&& !methodName.startsWith("jjt")
|
||||
&& !FILTERED_OUT_NAMES.contains(methodName);
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,12 @@
|
||||
package net.sourceforge.pmd.lang.ast.xpath.saxon;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
|
||||
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.BooleanValue;
|
||||
import net.sf.saxon.value.EmptySequence;
|
||||
import net.sf.saxon.value.Int64Value;
|
||||
import net.sf.saxon.value.StringValue;
|
||||
import net.sf.saxon.value.Value;
|
||||
|
||||
/**
|
||||
@ -48,20 +45,7 @@ public class AttributeNode extends AbstractNodeInfo {
|
||||
public Value atomize() throws XPathException {
|
||||
if (value == null) {
|
||||
Object v = attribute.getValue();
|
||||
// TODO Need to handle the full range of types, is there something
|
||||
// Saxon can do to help?
|
||||
if (v instanceof String) {
|
||||
value = new StringValue((String) v);
|
||||
} else if (v instanceof Boolean) {
|
||||
value = BooleanValue.get(((Boolean) v).booleanValue());
|
||||
} else if (v instanceof Integer) {
|
||||
value = Int64Value.makeIntegerValue((Integer) v);
|
||||
} else if (v == null) {
|
||||
value = EmptySequence.getInstance();
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Unable to create ValueRepresentaton for attribute value: " + v + " of type " + v.getClass());
|
||||
}
|
||||
value = SaxonXPathRuleQuery.getAtomicRepresentation(v);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -14,12 +14,9 @@ import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.saxon.DocumentNode;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode;
|
||||
import net.sourceforge.pmd.lang.xpath.Initializer;
|
||||
import net.sourceforge.pmd.properties.BooleanProperty;
|
||||
import net.sourceforge.pmd.properties.EnumeratedProperty;
|
||||
import net.sourceforge.pmd.properties.IntegerProperty;
|
||||
import net.sourceforge.pmd.properties.PropertyDescriptor;
|
||||
import net.sourceforge.pmd.properties.StringProperty;
|
||||
|
||||
import net.sf.saxon.om.Item;
|
||||
import net.sf.saxon.om.ValueRepresentation;
|
||||
import net.sf.saxon.sxpath.AbstractStaticContext;
|
||||
import net.sf.saxon.sxpath.IndependentContext;
|
||||
@ -29,27 +26,36 @@ import net.sf.saxon.sxpath.XPathExpression;
|
||||
import net.sf.saxon.sxpath.XPathStaticContext;
|
||||
import net.sf.saxon.sxpath.XPathVariable;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
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.EmptySequence;
|
||||
import net.sf.saxon.value.FloatValue;
|
||||
import net.sf.saxon.value.Int64Value;
|
||||
import net.sf.saxon.value.SequenceExtent;
|
||||
import net.sf.saxon.value.StringValue;
|
||||
import net.sf.saxon.value.UntypedAtomicValue;
|
||||
|
||||
|
||||
/**
|
||||
* This is a Saxon based XPathRule query.
|
||||
*/
|
||||
public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
|
||||
// Mapping from Node name to applicable XPath queries
|
||||
private XPathExpression xpathExpression;
|
||||
private List<XPathVariable> xpathVariables;
|
||||
|
||||
private static final int MAX_CACHE_SIZE = 20;
|
||||
private static final Map<Node, DocumentNode> CACHE = new LinkedHashMap<Node, DocumentNode>(MAX_CACHE_SIZE) {
|
||||
private static final long serialVersionUID = -7653916493967142443L;
|
||||
|
||||
|
||||
protected boolean removeEldestEntry(final Map.Entry<Node, DocumentNode> eldest) {
|
||||
return size() > MAX_CACHE_SIZE;
|
||||
}
|
||||
};
|
||||
// Mapping from Node name to applicable XPath queries
|
||||
private XPathExpression xpathExpression;
|
||||
private List<XPathVariable> xpathVariables;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -59,6 +65,7 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
return XPATH_1_0_COMPATIBILITY.equals(version) || XPATH_2_0.equals(version);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -83,31 +90,7 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
String name = xpathVariable.getVariableQName().getLocalName();
|
||||
for (Map.Entry<PropertyDescriptor<?>, Object> entry : super.properties.entrySet()) {
|
||||
if (name.equals(entry.getKey().name())) {
|
||||
PropertyDescriptor<?> propertyDescriptor = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
ValueRepresentation valueRepresentation;
|
||||
|
||||
// TODO Need to handle null values?
|
||||
// TODO Need to handle more PropertyDescriptors, is
|
||||
// there an easy factory in Saxon we can use for this?
|
||||
if (propertyDescriptor instanceof StringProperty) {
|
||||
valueRepresentation = new StringValue((String) value);
|
||||
} else if (propertyDescriptor instanceof BooleanProperty) {
|
||||
valueRepresentation = BooleanValue.get((Boolean) value);
|
||||
} else if (propertyDescriptor instanceof IntegerProperty) {
|
||||
valueRepresentation = Int64Value.makeIntegerValue((Integer) value);
|
||||
} else if (propertyDescriptor instanceof EnumeratedProperty) {
|
||||
if (value instanceof String) {
|
||||
valueRepresentation = new StringValue((String) value);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Unable to create ValueRepresentaton for non-String EnumeratedProperty value: "
|
||||
+ value);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Unable to create ValueRepresentaton for PropertyDescriptor: "
|
||||
+ propertyDescriptor);
|
||||
}
|
||||
ValueRepresentation valueRepresentation = getRepresentation(entry.getKey(), entry.getValue());
|
||||
xpathDynamicContext.setVariable(xpathVariable, valueRepresentation);
|
||||
}
|
||||
}
|
||||
@ -123,6 +106,24 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
private ValueRepresentation getRepresentation(PropertyDescriptor<?> descriptor, Object value) {
|
||||
if (descriptor.isMultiValue()) {
|
||||
List<?> val = (List<?>) value;
|
||||
if (val.isEmpty()) {
|
||||
return EmptySequence.getInstance();
|
||||
}
|
||||
Item[] converted = new Item[val.size()];
|
||||
for (int i = 0; i < val.size(); i++) {
|
||||
converted[i] = getAtomicRepresentation(val.get(i));
|
||||
}
|
||||
return new SequenceExtent(converted);
|
||||
} else {
|
||||
return getAtomicRepresentation(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private DocumentNode getDocumentNode(Node node) {
|
||||
// Get the root AST node
|
||||
Node root = node;
|
||||
@ -142,6 +143,7 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
return documentNode;
|
||||
}
|
||||
|
||||
|
||||
private void initializeXPathExpression() {
|
||||
if (xpathExpression != null) {
|
||||
return;
|
||||
@ -178,4 +180,36 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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(Object value) {
|
||||
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 {
|
||||
// We could maybe use UntypedAtomicValue
|
||||
throw new RuntimeException("Unable to create ValueRepresentation for value of type: " + value.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,29 +23,29 @@ public class PropertyDescriptorUtil {
|
||||
static {
|
||||
Map<String, PropertyDescriptorExternalBuilder<?>> temp = new HashMap<>(18);
|
||||
temp.put("Boolean", BooleanProperty.extractor());
|
||||
temp.put("List<Boolean>", BooleanMultiProperty.extractor());
|
||||
temp.put("List[Boolean]", BooleanMultiProperty.extractor());
|
||||
|
||||
temp.put("String", StringProperty.extractor());
|
||||
temp.put("List<String>", StringMultiProperty.extractor());
|
||||
temp.put("List[String]", StringMultiProperty.extractor());
|
||||
temp.put("Character", CharacterProperty.extractor());
|
||||
temp.put("List<Character>", CharacterMultiProperty.extractor());
|
||||
temp.put("List[Character]", CharacterMultiProperty.extractor());
|
||||
|
||||
|
||||
temp.put("Integer", IntegerProperty.extractor());
|
||||
temp.put("List<Integer>", IntegerMultiProperty.extractor());
|
||||
temp.put("List[Integer]", IntegerMultiProperty.extractor());
|
||||
temp.put("Long", LongProperty.extractor());
|
||||
temp.put("List<Long>", LongMultiProperty.extractor());
|
||||
temp.put("List[Long]", LongMultiProperty.extractor());
|
||||
temp.put("Float", FloatProperty.extractor());
|
||||
temp.put("List<Float>", FloatMultiProperty.extractor());
|
||||
temp.put("List[Float]", FloatMultiProperty.extractor());
|
||||
temp.put("Double", DoubleProperty.extractor());
|
||||
temp.put("List<Double>", DoubleMultiProperty.extractor());
|
||||
// temp.put("Enum", EnumeratedProperty.FACTORY); // TODO:cf implement that
|
||||
// temp.put("List<Enum>", EnumeratedMultiProperty.FACTORY);
|
||||
temp.put("List[Double]", DoubleMultiProperty.extractor());
|
||||
// temp.put("Enum", EnumeratedProperty.FACTORY); // TODO:cf we need new syntax in the xml to support that
|
||||
// temp.put("List[Enum]", EnumeratedMultiProperty.FACTORY);
|
||||
|
||||
temp.put("Class", TypeProperty.extractor());
|
||||
temp.put("List<Class>", TypeMultiProperty.extractor());
|
||||
temp.put("List[Class]", TypeMultiProperty.extractor());
|
||||
temp.put("Method", MethodProperty.extractor());
|
||||
temp.put("List<Method>", MethodMultiProperty.extractor());
|
||||
temp.put("List[Method]", MethodMultiProperty.extractor());
|
||||
|
||||
temp.put("File", FileProperty.extractor());
|
||||
|
||||
|
@ -179,7 +179,7 @@ public class RuleSetFactoryTest {
|
||||
+ "class=\"net.sourceforge.pmd.lang.rule.XPathRule\" language=\"dummy\">\n"
|
||||
+ " <description>Please move your class to the right folder(rest \nfolder)</description>\n"
|
||||
+ " <priority>2</priority>\n <properties>\n <property name=\"packageRegEx\""
|
||||
+ " value=\"com.aptsssss|com.abc\" \ntype=\"List<String>\" "
|
||||
+ " value=\"com.aptsssss|com.abc\" \ntype=\"List[String]\" "
|
||||
+ "description=\"valid packages\"/>\n </properties></rule></ruleset>");
|
||||
PropertyDescriptor<List<String>> prop = (PropertyDescriptor<List<String>>) r.getPropertyDescriptor("packageRegEx");
|
||||
List<String> values = r.getProperty(prop);
|
||||
@ -194,7 +194,7 @@ public class RuleSetFactoryTest {
|
||||
+ " instead.\" \n" + "class=\"net.sourceforge.pmd.lang.rule.XPathRule\" language=\"dummy\">\n"
|
||||
+ " <description>Please move your class to the right folder(rest \nfolder)</description>\n"
|
||||
+ " <priority>2</priority>\n <properties>\n <property name=\"packageRegEx\""
|
||||
+ " value=\"com.aptsssss,com.abc\" \ntype=\"List<String>\" delimiter=\",\" "
|
||||
+ " value=\"com.aptsssss,com.abc\" \ntype=\"List[String]\" delimiter=\",\" "
|
||||
+ "description=\"valid packages\"/>\n"
|
||||
+ " </properties></rule>" + "</ruleset>");
|
||||
PropertyDescriptor<List<String>> prop = (PropertyDescriptor<List<String>>) r.getPropertyDescriptor("packageRegEx");
|
||||
|
@ -95,7 +95,7 @@ public abstract class AbstractPropertyDescriptorTester<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final PropertyDescriptorExternalBuilder<List<T>> getMultiFactory() {
|
||||
return (PropertyDescriptorExternalBuilder<List<T>>) PropertyDescriptorUtil.factoryFor("List<" + typeName + ">");
|
||||
return (PropertyDescriptorExternalBuilder<List<T>>) PropertyDescriptorUtil.factoryFor("List[" + typeName + "]");
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user