Merge branch 'issue-2218'

This commit is contained in:
Clément Fournier
2020-01-17 18:31:38 +01:00
6 changed files with 72 additions and 3 deletions

View File

@ -133,6 +133,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati
* pmd-core
* Many methods on the {% jdoc core::lang.ast.Node %} interface
and {% jdoc core::lang.ast.AbstractNode %} base class. See their javadoc for details.
* {% jdoc !!core::lang.ast.Node#isFindBoundary() %} is deprecated for XPath queries.
* pmd-java
* {% jdoc java::lang.java.AbstractJavaParser %}
* {% jdoc java::lang.java.AbstractJavaHandler %}

View File

@ -12,6 +12,7 @@ import org.w3c.dom.Document;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute;
import net.sourceforge.pmd.lang.dfa.DataFlowNode;
/**
@ -202,7 +203,11 @@ public interface Node {
* look past such boundaries by default, which is usually the expected thing
* to do. For example, in Java, lambdas and nested classes are considered
* find boundaries.
*
* <p>Note: This attribute is deprecated for XPath queries. It is not useful
* for XPath queries and will be removed with PMD 7.0.0.
*/
@DeprecatedAttribute
boolean isFindBoundary();

View File

@ -16,6 +16,7 @@ import java.util.logging.Logger;
import net.sourceforge.pmd.annotation.Experimental;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute;
/**
* Represents an XPath attribute of a specific node.
@ -31,7 +32,7 @@ public class Attribute {
private static final Logger LOG = Logger.getLogger(Attribute.class.getName());
private static final ConcurrentMap<String, Boolean> DETECTED_DEPRECATED_ATTRIBUTES = new ConcurrentHashMap<>();
static final ConcurrentMap<String, Boolean> DETECTED_DEPRECATED_ATTRIBUTES = new ConcurrentHashMap<>();
private static final Object[] EMPTY_OBJ_ARRAY = new Object[0];
@ -72,12 +73,17 @@ public class Attribute {
return method == null ? String.class : method.getReturnType();
}
private boolean isAttributeDeprecated() {
return method != null && (method.isAnnotationPresent(Deprecated.class)
|| method.isAnnotationPresent(DeprecatedAttribute.class));
}
public Object getValue() {
if (value != null) {
return value.get(0);
}
if (method.isAnnotationPresent(Deprecated.class) && LOG.isLoggable(Level.WARNING)
if (LOG.isLoggable(Level.WARNING) && isAttributeDeprecated()
&& DETECTED_DEPRECATED_ATTRIBUTES.putIfAbsent(getLoggableAttributeName(), Boolean.TRUE) == null) {
// this message needs to be kept in sync with PMDCoverageTest / BinaryDistributionIT
LOG.warning("Use of deprecated attribute '" + getLoggableAttributeName() + "' in XPath query");

View File

@ -0,0 +1,25 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ast.xpath.internal;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Node attribute getter methods might be annotated with {@code DeprecatedAttribute}
* to mark the attribute as deprecated for XPath. Unlike {@link Deprecated}, this
* annotation does not deprecate the method for java usage.
*
* @since 6.21.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DeprecatedAttribute {
}

View File

@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.ast;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute;
/**
* @author Clément Fournier
* @since 6.3.0
@ -20,4 +22,11 @@ public class DummyNodeWithDeprecatedAttribute extends DummyNode {
public int getSize() {
return 2;
}
// this is a attribute that is deprecated for xpath, because it will be removed.
// it should still be available via Java.
@DeprecatedAttribute
public String getName() {
return "foo";
}
}

View File

@ -16,10 +16,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hamcrest.Matchers;
import org.hamcrest.collection.IsMapContaining;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import net.sourceforge.pmd.junit.JavaUtilLoggingRule;
import net.sourceforge.pmd.lang.ast.DummyNode;
import net.sourceforge.pmd.lang.ast.DummyNodeWithDeprecatedAttribute;
import net.sourceforge.pmd.lang.ast.Node;
@ -30,10 +33,30 @@ import net.sourceforge.pmd.lang.ast.Node;
*/
public class AttributeAxisIteratorTest {
@Rule
public JavaUtilLoggingRule loggingRule = new JavaUtilLoggingRule(Attribute.class.getName());
/**
* Verifies that attributes are returned, even if they are deprecated.
* Deprecated attributes are still accessible, but a warning is logged, when
* the value is used.
*/
@Test
public void testAttributeDeprecation() {
// make sure, we log
Attribute.DETECTED_DEPRECATED_ATTRIBUTES.clear();
Node dummy = new DummyNodeWithDeprecatedAttribute(2);
assertThat(toMap(new AttributeAxisIterator(dummy)), IsMapContaining.hasKey("Size"));
Map<String, Attribute> attributes = toMap(new AttributeAxisIterator(dummy));
assertThat(attributes, IsMapContaining.hasKey("Size"));
assertThat(attributes, IsMapContaining.hasKey("Name"));
assertThat(attributes.get("Size").getStringValue(), Matchers.is("2"));
assertThat(attributes.get("Name").getStringValue(), Matchers.is("foo"));
String log = loggingRule.getLog();
assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Size' in XPath query"));
assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Name' in XPath query"));
}
/**