diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java index a1259b816d..8c9ed3e59d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Objects; import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; @@ -64,11 +65,30 @@ public class Attribute { return method == null ? String.class : method.getReturnType(); } + @InternalApi public boolean isAttributeDeprecated() { return method != null && (method.isAnnotationPresent(Deprecated.class) || method.isAnnotationPresent(DeprecatedAttribute.class)); } + /** + * Returns null for "not deprecated", empty string for "deprecated for removal", + * otherwise name of replacement attribute. + */ + @InternalApi + public String replacementIfDeprecated() { + if (method == null) { + return null; + } else { + DeprecatedAttribute annot = method.getAnnotation(DeprecatedAttribute.class); + if (annot == null) { + return method.isAnnotationPresent(Deprecated.class) ? DeprecatedAttribute.NO_REPLACEMENT + : null; + } + return annot.replaceWith(); + } + } + public Object getValue() { if (value != null) { return value.get(0); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttrLogger.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttrLogger.java index 3dd180f211..22a9a64d4a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttrLogger.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttrLogger.java @@ -64,12 +64,17 @@ public abstract class DeprecatedAttrLogger { @Override public void recordUsageOf(Attribute attribute) { - if (attribute.isAttributeDeprecated()) { + String replacement = attribute.replacementIfDeprecated(); + if (replacement != null) { String name = getLoggableAttributeName(attribute); Boolean b = deprecated.putIfAbsent(name, Boolean.TRUE); if (b == null) { // this message needs to be kept in sync with PMDCoverageTest / BinaryDistributionIT - LOG.warning("Use of deprecated attribute '" + name + "' by rule " + ruleToString()); + String msg = "Use of deprecated attribute '" + name + "' by rule " + ruleToString(); + if (!replacement.isEmpty()) { + msg += ", please use " + replacement + " instead"; + } + LOG.warning(msg); } } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java index 75e80d4f5f..cb443d35ae 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java @@ -22,4 +22,13 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DeprecatedAttribute { + + String NO_REPLACEMENT = ""; + + + /** + * The simple name of the attribute to use for replacement. + * If empty, then the attribute is deprecated for removal. + */ + String replaceWith() default NO_REPLACEMENT; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java index 9da1b6753c..7a919967ef 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java @@ -53,11 +53,6 @@ public class AttributeNode extends BaseNodeInfo { : parent.document.getAttrCtx(); } - @Override - public ElementNode getParent() { - return parent; - } - @Override public Value atomize() { getAttrCtx().recordUsageOf(attribute); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java index b2176402ff..9d6c995cb9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.annotation.InternalApi; +import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; /** * Represents an addition operation on two or more values, or string concatenation. @@ -40,6 +41,16 @@ public class ASTAdditiveExpression extends AbstractJavaTypeNode { } + /** + * @deprecated Use {@link #getOperator()} + */ + @Override + @Deprecated + @DeprecatedAttribute(replaceWith = "@Operator") + public String getImage() { + return super.getImage(); + } + /** * Returns the image of the operator, i.e. "+" or "-". */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java index 2c39b1dbf8..d672a49046 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.List; import java.util.Locale; +import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil; import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName; @@ -32,6 +33,7 @@ public interface ASTAnyTypeDeclaration extends TypeNode, JavaQualifiableNode, Ac * @deprecated Use {@link #getSimpleName()} */ @Deprecated + @DeprecatedAttribute(replaceWith = "@SimpleName") @Override String getImage();