diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index c9c55694ab..18dff08b2b 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -2282,47 +2282,32 @@ void RSIGNEDSHIFT() #void: /* Annotation syntax follows. */ -void Annotation() #void: +void Annotation(): {} { - LOOKAHEAD( "@" VoidName() "(" ( "=" | ")" )) - NormalAnnotation() -| - LOOKAHEAD( "@" VoidName() "(" ) - SingleMemberAnnotation() -| - MarkerAnnotation() + "@" jjtThis.name=VoidName() [ AnnotationMemberList() ] } -void AnnotationBase(Node n) #void: -{String name = null;} -{ - "@" name=VoidName() {n.setImage(name);} -} - -void NormalAnnotation(): +void AnnotationMemberList(): {} { - AnnotationBase(jjtThis) "(" [ MemberValuePairs() ] ")" + "(" + ( LOOKAHEAD( "=") + MemberValuePair() ( "," MemberValuePair() )* + | [ ShorthandAnnotationValue() ] + ) + ")" } -void MarkerAnnotation(): -{} +void ShorthandAnnotationValue() #MemberValuePair: { - AnnotationBase(jjtThis) + jjtThis.setImage("value"); + jjtThis.setShorthand(); +} +{ + MemberValue() } -void SingleMemberAnnotation(): -{} -{ - AnnotationBase(jjtThis) "(" MemberValue() ")" -} - -void MemberValuePairs() #void: -{} -{ - MemberValuePair() ( "," MemberValuePair() )* -} void MemberValuePair(): {} @@ -2334,11 +2319,8 @@ void MemberValue() #void: {} { Annotation() - | - MemberValueArrayInitializer() - | - // Constant expression - ConditionalExpression() + | MemberValueArrayInitializer() + | ConditionalExpression() // Constant expression } void MemberValueArrayInitializer(): @@ -2471,12 +2453,8 @@ String VoidName() #void: JavaccToken t; } { - t= - { - s.append(t.getImage()); - } - ( LOOKAHEAD(2) "." t= - {s.append('.').append(t.getImage());} + t= { s.append(t.getImage()); } + ( LOOKAHEAD(2) "." t= {s.append('.').append(t.getImage());} )* {return s.toString();} } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java index 20b8265829..b709760fc6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java @@ -4,38 +4,83 @@ package net.sourceforge.pmd.lang.java.ast; +import java.util.Iterator; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import net.sourceforge.pmd.lang.ast.NodeStream; + /** - * Represents an annotation. This node has three specific syntactic variants, - * represented by nodes that implement this interface. + * Represents an annotation. * *
  *
- * Annotation ::= {@linkplain ASTNormalAnnotation NormalAnnotation}
- *              | {@linkplain ASTSingleMemberAnnotation SingleMemberAnnotation}
- *              | {@linkplain ASTMarkerAnnotation MarkerAnnotation}
+ * Annotation ::= "@" Name {@link ASTAnnotationMemberList AnnotationMemberList}?
  *
  * 
*/ -public interface ASTAnnotation extends TypeNode, ASTMemberValue { +public final class ASTAnnotation extends AbstractJavaTypeNode implements TypeNode, ASTMemberValue, Iterable { + + String name; + + ASTAnnotation(int id) { + super(id); + } /** * Returns the name of the annotation as it is used, * eg {@code java.lang.Override} or {@code Override}. */ - default String getAnnotationName() { - return getImage(); + public String getAnnotationName() { + return name; } + @Override + @Deprecated + public String getImage() { + return name; + } + /** * Returns the simple name of the annotation. */ - default String getSimpleName() { - String[] split = getImage().split("\\."); + public String getSimpleName() { + String[] split = getAnnotationName().split("\\."); return split[split.length - 1]; } -} + /** + * Returns the list of members, or null if there is none. + */ + public @Nullable ASTAnnotationMemberList getMemberList() { + return children().first(ASTAnnotationMemberList.class); + } + /** + * Returns the stream of explicit members for this annotation. + */ + public NodeStream getMembers() { + return children(ASTAnnotationMemberList.class).children(ASTMemberValuePair.class); + } + + + @Override + public Iterator iterator() { + return children(ASTMemberValuePair.class).iterator(); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMemberList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMemberList.java new file mode 100644 index 0000000000..2cedd5513c --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMemberList.java @@ -0,0 +1,56 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import java.util.Iterator; + +import net.sourceforge.pmd.lang.ast.NodeStream; + +/** + * Represents the list of {@link ASTMemberValuePair member-value pairs} + * in an {@link ASTAnnotation annotation}. + * + *
+ *
+ * AnnotationMemberList ::= "(" {@link ASTMemberValuePair MemberValuePair} ( "," {@link ASTMemberValuePair MemberValuePair} )* ")"
+ *                        | "(" {@link ASTMemberValuePair ValueShorthand} ")"
+ *                        | "(" ")"
+ *
+ * 
+ */ +public final class ASTAnnotationMemberList extends AbstractJavaNode implements Iterable { + + ASTAnnotationMemberList(int id) { + super(id); + } + + + @Override + public ASTAnnotation getParent() { + return (ASTAnnotation) super.getParent(); + } + + @Override + @SuppressWarnings("unchecked") + public NodeStream children() { + return (NodeStream) super.children(); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } + + @Override + public Iterator iterator() { + return children().iterator(); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayType.java index 946a1f7829..56eabdca3d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayType.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.List; +import net.sourceforge.pmd.lang.ast.NodeStream; /** * Represents an array type. @@ -23,11 +23,8 @@ public final class ASTArrayType extends AbstractJavaTypeNode implements ASTRefer @Override - public List getDeclaredAnnotations() { - // an array type's annotations are on its dimensions - // any annotations found before the element type apply to the - // element type - return ((ASTArrayTypeDim) getDimensions().getLastChild()).getDeclaredAnnotations(); + public NodeStream getDeclaredAnnotations() { + return getDimensions().getLastChild().getDeclaredAnnotations(); } public ASTArrayDimensions getDimensions() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java index c680680794..565b1fc0bc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java @@ -15,8 +15,11 @@ package net.sourceforge.pmd.lang.java.ast; * * @see ASTSingleMemberAnnotation * @see ASTNormalAnnotation + * + * @deprecated Replaced with {@link ASTAnnotation} */ -public final class ASTMarkerAnnotation extends AbstractJavaTypeNode implements ASTAnnotation { +@Deprecated +public final class ASTMarkerAnnotation extends AbstractJavaTypeNode { ASTMarkerAnnotation(int id) { super(id); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java index a4afe7c074..3055da7a26 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java @@ -5,38 +5,54 @@ package net.sourceforge.pmd.lang.java.ast; /** - * Represents a single member-value pair in a {@linkplain ASTNormalAnnotation NormalAnnotation}. + * Represents a single pair of member name to value in an annotation. + * This node also represents the shorthand syntax, see {@link #isShorthand()}. * *
  *
- * MemberValuePair ::=  <IDENTIFIER> "=" {@linkplain ASTMemberValue MemberValue}
+ * MemberValuePair ::= <IDENTIFIER> "=" {@linkplain ASTMemberValue MemberValue}
+ *
+ * ValueShorthand  ::= {@linkplain ASTMemberValue MemberValue}
  *
  * 
*/ public final class ASTMemberValuePair extends AbstractJavaNode { + + private boolean isShorthand; + ASTMemberValuePair(int id) { super(id); } /** * Returns the name of the member set by this pair. + * This returns {@code "value"} if this is a shorthand declaration. */ - public String getMemberName() { + public String getName() { return getImage(); } + /** + * Returns true if this is a shorthand for the {@code value} attribute. + * For example, {@code @A("v")} has exactly the same structure as + * {@code @A(value = "v")}, except this attribute returns true for + * the first one only. + */ + public boolean isShorthand() { + return isShorthand; + } /** * Returns the value of the member set by this pair. */ - public ASTMemberValue getMemberValue() { + public ASTMemberValue getValue() { return (ASTMemberValue) getChild(0); } @Override - public ASTNormalAnnotation getParent() { - return (ASTNormalAnnotation) super.getParent(); + public ASTAnnotationMemberList getParent() { + return (ASTAnnotationMemberList) super.getParent(); } @@ -50,4 +66,8 @@ public final class ASTMemberValuePair extends AbstractJavaNode { public void jjtAccept(SideEffectingVisitor visitor, T data) { visitor.visit(this, data); } + + void setShorthand() { + this.isShorthand = true; + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java index 4ef7407b71..a050934f57 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java @@ -18,8 +18,11 @@ import java.util.Iterator; * * @see ASTSingleMemberAnnotation * @see ASTMarkerAnnotation + * @deprecated Replaced with {@link ASTAnnotation} */ -public final class ASTNormalAnnotation extends AbstractJavaTypeNode implements ASTAnnotation, Iterable { +@Deprecated +public final class ASTNormalAnnotation extends AbstractJavaTypeNode implements Iterable { + ASTNormalAnnotation(int id) { super(id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java index 058a0bef0b..a42efd2ed7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java @@ -15,8 +15,11 @@ package net.sourceforge.pmd.lang.java.ast; * * @see ASTMarkerAnnotation * @see ASTNormalAnnotation + * @deprecated Replaced with {@link ASTAnnotation} */ -public final class ASTSingleMemberAnnotation extends AbstractJavaTypeNode implements ASTAnnotation { +@Deprecated +public final class ASTSingleMemberAnnotation extends AbstractJavaTypeNode { + ASTSingleMemberAnnotation(int id) { super(id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java index 05f84f456d..101fb7ab05 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java @@ -5,8 +5,6 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.List; - import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -30,11 +28,6 @@ public final class ASTTypeParameter extends AbstractJavaTypeNode implements Anno super(id); } - @Override - public List getDeclaredAnnotations() { - return children(ASTAnnotation.class).toList(); - } - /** * Returns the name of the type variable introduced by this declaration. */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java index f5918859f0..d24be8141b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java @@ -11,6 +11,8 @@ import java.util.Set; import org.checkerframework.checker.nullness.qual.NonNull; +import net.sourceforge.pmd.lang.ast.NodeStream; + /** * A node that owns a {@linkplain ASTModifierList modifier list}. * @@ -31,10 +33,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; */ public interface AccessNode extends Annotatable { - @Override - default List getDeclaredAnnotations() { - return getModifiers().children(ASTAnnotation.class).toList(); + default NodeStream getDeclaredAnnotations() { + return getModifiers().children(ASTAnnotation.class); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Annotatable.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Annotatable.java index 12afe8904f..6a136e705a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Annotatable.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Annotatable.java @@ -4,11 +4,9 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.Collection; -import java.util.List; - -import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.function.Predicate; +import net.sourceforge.pmd.lang.ast.NodeStream; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; /** @@ -24,54 +22,25 @@ public interface Annotatable extends JavaNode { /** * Returns all annotations present on this node. */ - default List getDeclaredAnnotations() { - return this.findChildrenOfType(ASTAnnotation.class); - } - - - /** - * Returns the annotation with the given qualified name if it is present, - * otherwise returns null. The argument should be a qualified name, though - * this method will find also usages of an annotation that use the simple - * name if it is in scope. - * - *

E.g. {@code getAnnotation("java.lang.Override")} will find both - * {@code @java.lang.Override} and {@code @Override}. - */ - @Nullable - default ASTAnnotation getAnnotation(String annotQualifiedName) { - // TODO use node streams - List annotations = getDeclaredAnnotations(); - for (ASTAnnotation annotation : annotations) { - if (TypeHelper.isA(annotation, annotQualifiedName)) { - return annotation; - } - } - return null; - } - - - /** - * Returns true if any annotation in the given collection is present, - * using {@link #isAnnotationPresent(String)}, otherwise false. - */ - default boolean isAnyAnnotationPresent(Collection annotQualifiedNames) { - // TODO use node streams - for (String annotQualifiedName : annotQualifiedNames) { - if (isAnnotationPresent(annotQualifiedName)) { - return true; - } - } - return false; + default NodeStream getDeclaredAnnotations() { + return children(ASTAnnotation.class); } /** * Returns true if an annotation with the given qualified name is - * applied to this node. In this case, {@link #getAnnotation(String)} - * will not return null. + * applied to this node. */ default boolean isAnnotationPresent(String annotQualifiedName) { - return getAnnotation(annotQualifiedName) != null; + return getDeclaredAnnotations().any(t -> TypeHelper.isA(t, annotQualifiedName)); + } + + + /** + * Returns true if an annotation with the given type is + * applied to this node. + */ + default boolean isAnnotationPresent(Class type) { + return getDeclaredAnnotations().any((Predicate) t -> TypeHelper.subclasses(t, type)); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java index 8a52ba6ce1..bc8055b38e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java @@ -25,24 +25,6 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; public class JavaParserVisitorAdapter implements JavaParserVisitor { - public Object visit(ASTAnnotation node, Object data) { - return visit((JavaNode) node, data); - } - - @Override - public Object visit(ASTMarkerAnnotation node, Object data) { - return visit((ASTAnnotation) node, data); - } - - @Override - public Object visit(ASTSingleMemberAnnotation node, Object data) { - return visit((ASTAnnotation) node, data); - } - - @Override - public Object visit(ASTNormalAnnotation node, Object data) { - return visit((ASTAnnotation) node, data); - } public Object visit(ASTType node, Object data) { return visit((JavaNode) node, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java index 6af146c604..9d60f87c06 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java @@ -15,25 +15,6 @@ package net.sourceforge.pmd.lang.java.ast; public class SideEffectingVisitorAdapter implements SideEffectingVisitor { - public void visit(ASTAnnotation node, T data) { - visit((JavaNode) node, data); - } - - @Override - public void visit(ASTSingleMemberAnnotation node, T data) { - visit((ASTAnnotation) node, data); - } - - @Override - public void visit(ASTNormalAnnotation node, T data) { - visit((ASTAnnotation) node, data); - } - - @Override - public void visit(ASTMarkerAnnotation node, T data) { - visit((ASTAnnotation) node, data); - } - // TODO delegation diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java index a6df69870f..81d3335341 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java @@ -38,6 +38,6 @@ public abstract class AbstractIgnoredAnnotationRule extends AbstractJavaRule { * @return true if the annotation has been found, otherwise false */ protected boolean hasIgnoredAnnotation(Annotatable node) { - return node.isAnyAnnotationPresent(getProperty(ignoredAnnotationsDescriptor)); + return getProperty(ignoredAnnotationsDescriptor).stream().anyMatch(node::isAnnotationPresent); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java index f6883b3196..2ba13ebc45 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java @@ -136,6 +136,6 @@ public class AbstractLombokAwareRule extends AbstractIgnoredAnnotationRule { * @return true if a lombok annotation has been found */ protected boolean hasLombokAnnotation(Annotatable node) { - return node.isAnyAnnotationPresent(LOMBOK_ANNOTATIONS); + return LOMBOK_ANNOTATIONS.stream().anyMatch(node::isAnnotationPresent); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java index bf0762a71d..d6e4ec3d4d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java @@ -18,7 +18,6 @@ import java.util.Stack; import java.util.logging.Logger; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant; @@ -213,11 +212,9 @@ public class MissingOverrideRule extends AbstractJavaRule { return super.visit(node, data); } - for (ASTAnnotation annot : node.getDeclaredAnnotations()) { - if (Override.class.equals(annot.getType())) { - // we assume the compiler has already checked it, so it's correct - return super.visit(node, data); - } + if (node.isAnnotationPresent(Override.class)) { + // we assume the compiler has already checked it, so it's correct + return super.visit(node, data); } try { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java index 0111277c61..96315124ff 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java @@ -125,6 +125,7 @@ public class UnusedFormalParameterRule extends AbstractJavaRule { } private boolean hasOverrideAnnotation(ASTMethodDeclaration node) { + int childIndex = node.getIndexInParent(); for (int i = 0; i < childIndex; i++) { Node previousSibling = node.getParent().getChild(i); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java index b805a0cabc..0fab28c792 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java @@ -73,7 +73,7 @@ public class MethodNamingConventionsRule extends AbstractNamingConventionRule memberValuePairs = annotation.findDescendantsOfType(ASTMemberValuePair.class); - - for (ASTMemberValuePair memberValuePair : memberValuePairs) { - // to set the access level of a constructor in lombok, you set the access property on the annotation - if ("access".equals(memberValuePair.getImage())) { - List names = memberValuePair.findDescendantsOfType(ASTName.class); - - for (ASTName name : names) { - // check to see if the value of the member value pair ends PRIVATE. This is from the AccessLevel enum in Lombok - if (name.getImage().endsWith("PRIVATE")) { - // if the constructor is found and the accesslevel is private no need to check anything else - return true; - } - } - } - } - } - - return false; + return parent.getDeclaredAnnotations() + .filter((Predicate) t -> TypeHelper.isA(t, "lombok.NoArgsConstructor")) + .flatMap(ASTAnnotation::getMembers) + // to set the access level of a constructor in lombok, you set the access property on the annotation + .filterMatching(ASTMemberValuePair::getName, "access") + .map(ASTMemberValuePair::getValue) + // This is from the AccessLevel enum in Lombok + // if the constructor is found and the accesslevel is private no need to check anything else + .any(it -> it.getImage().equals("PRIVATE")); } private Node skipAnnotations(Node p) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java index 5316715051..91a5be5411 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java @@ -104,12 +104,7 @@ final class AnnotationSuppressionUtil { } private static boolean hasSuppressWarningsAnnotationFor(final Annotatable node, Rule rule) { - for (ASTAnnotation a : node.getDeclaredAnnotations()) { - if (annotationSuppresses(a, rule)) { - return true; - } - } - return false; + return node.getDeclaredAnnotations().any(it -> annotationSuppresses(it, rule)); } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTest.kt index 91759f5b92..1a9685cd76 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTest.kt @@ -6,9 +6,9 @@ package net.sourceforge.pmd.lang.java.ast import net.sourceforge.pmd.lang.ast.test.shouldBe import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Earliest +import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Latest import net.sourceforge.pmd.lang.java.ast.JavaVersion.J1_3 import net.sourceforge.pmd.lang.java.ast.JavaVersion.J1_5 -import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Latest /** * @author Clément Fournier @@ -30,16 +30,20 @@ class ASTAnnotationTest : ParserTestSpec({ inContext(AnnotationParsingCtx) { "@F" should parseAs { - child { + child { it::getAnnotationName shouldBe "F" it::getSimpleName shouldBe "F" + + it::getMemberList shouldBe null } } "@java.lang.Override" should parseAs { - child { + child { it::getAnnotationName shouldBe "java.lang.Override" it::getSimpleName shouldBe "Override" + + it::getMemberList shouldBe null } } } @@ -51,45 +55,63 @@ class ASTAnnotationTest : ParserTestSpec({ inContext(AnnotationParsingCtx) { "@F(\"ohio\")" should parseAs { - child { + child { it::getAnnotationName shouldBe "F" it::getSimpleName shouldBe "F" - it::getMemberValue shouldBe stringLit("\"ohio\"") + it::getMemberList shouldBe child { + shorthandMemberValue { + stringLit("\"ohio\"") + } + } } } "@org.F({java.lang.Math.PI})" should parseAs { - child { + child { it::getAnnotationName shouldBe "org.F" it::getSimpleName shouldBe "F" - it::getMemberValue shouldBe child { - child { - it::getFieldName shouldBe "PI" - ambiguousName("java.lang.Math") + it::getMemberList shouldBe child { + shorthandMemberValue { + child { + child { + it::getFieldName shouldBe "PI" + ambiguousName("java.lang.Math") + } + } } } } } "@org.F({@Aha, @Oh})" should parseAs { - child { + child { it::getAnnotationName shouldBe "org.F" it::getSimpleName shouldBe "F" - it::getMemberValue shouldBe child { - annotation("Aha") - annotation("Oh") + + it::getMemberList shouldBe child { + shorthandMemberValue { + child { + annotation("Aha") + annotation("Oh") + } + } } } } "@org.F(@Oh)" should parseAs { - child { + child { it::getAnnotationName shouldBe "org.F" it::getSimpleName shouldBe "F" - it::getMemberValue shouldBe annotation("Oh") + + it::getMemberList shouldBe child { + shorthandMemberValue { + annotation("Oh") + } + } } } } @@ -101,44 +123,37 @@ class ASTAnnotationTest : ParserTestSpec({ inContext(AnnotationParsingCtx) { "@F(a=\"ohio\")" should parseAs { - child { + child { it::getAnnotationName shouldBe "F" it::getSimpleName shouldBe "F" - memberValuePair("a") { - stringLit("\"ohio\"") + + it::getMemberList shouldBe child { + memberValuePair("a") { + stringLit("\"ohio\"") + } } } } "@org.F(a={java.lang.Math.PI}, b=2)" should parseAs { - child { + child { it::getAnnotationName shouldBe "org.F" it::getSimpleName shouldBe "F" - memberValuePair("a") { - child { - child { - it::getFieldName shouldBe "PI" - ambiguousName("java.lang.Math") + + it::getMemberList shouldBe child { + memberValuePair("a") { + child { + fieldAccess("PI") { + ambiguousName("java.lang.Math") + } } } - } - memberValuePair("b") { - number() - } - } - } - - "@org.F({@Aha, @Oh})" should parseAs { - child { - it::getAnnotationName shouldBe "org.F" - it::getSimpleName shouldBe "F" - - it::getMemberValue shouldBe child { - annotation("Aha") - annotation("Oh") + memberValuePair("b") { + number() + } } } } @@ -146,28 +161,45 @@ class ASTAnnotationTest : ParserTestSpec({ """ @TestAnnotation({@SuppressWarnings({}), - @SuppressWarnings({"Beware the ides of March.",}), + @SuppressWarnings(value = {"Beware the ides of March.",}), @SuppressWarnings({"Look both ways", "Before Crossing",}), }) """ should parseAs { - child { + child { - it::getMemberValue shouldBe child { - child { + it::getMemberList shouldBe child { - it::getMemberValue shouldBe child {} - } - child { + shorthandMemberValue { - it::getMemberValue shouldBe child { - stringLit("\"Beware the ides of March.\"") - } - } - child { + child { + annotation { - it::getMemberValue shouldBe child { - stringLit("\"Look both ways\"") - stringLit("\"Before Crossing\"") + it::getMemberList shouldBe child { + shorthandMemberValue { + child {} + } + } + } + annotation { + it::getMemberList shouldBe child { + memberValuePair("value") { + it::isShorthand shouldBe false + child { + stringLit("\"Beware the ides of March.\"") + } + } + } + } + annotation { + it::getMemberList shouldBe child { + shorthandMemberValue { + child { + stringLit("\"Look both ways\"") + stringLit("\"Before Crossing\"") + } + } + } + } } } } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt index f347079cc6..a67e981a01 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt @@ -36,7 +36,7 @@ class ASTArrayTypeTest : ParserTestSpec({ arrayType { it::getElementType shouldBe classType("ArrayTypes") - it::getDeclaredAnnotations shouldBe fromChild> { + it::declaredAnnotationsList shouldBe fromChild> { arrayDim { } arrayDim { } @@ -44,7 +44,7 @@ class ASTArrayTypeTest : ParserTestSpec({ val lst = listOf(annotation("A")) - it::getDeclaredAnnotations shouldBe lst + it::declaredAnnotationsList shouldBe lst lst } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt index d2f47d13d3..b6e12c936f 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt @@ -56,11 +56,11 @@ class ASTCastExpressionTest : ParserTestSpec({ castExpr { it::getCastType shouldBe child { - it::getDeclaredAnnotations shouldBe emptyList() + it::declaredAnnotationsList shouldBe emptyList() classType("Foo") { // annotations nest on the inner node - it::getDeclaredAnnotations shouldBe listOf(annotation("F")) + it::declaredAnnotationsList shouldBe listOf(annotation("F")) } classType("Bar") @@ -76,15 +76,15 @@ class ASTCastExpressionTest : ParserTestSpec({ castExpr { it::getCastType shouldBe child { - it::getDeclaredAnnotations shouldBe emptyList() + it::declaredAnnotationsList shouldBe emptyList() classType("Foo") { // annotations nest on the inner node - it::getDeclaredAnnotations shouldBe listOf(annotation("F")) + it::declaredAnnotationsList shouldBe listOf(annotation("F")) } classType("Bar") { - it::getDeclaredAnnotations shouldBe listOf(annotation("B"), annotation("C")) + it::declaredAnnotationsList shouldBe listOf(annotation("B"), annotation("C")) } } @@ -140,3 +140,6 @@ class ASTCastExpressionTest : ParserTestSpec({ }) + +val Annotatable.declaredAnnotationsList: List + get() = declaredAnnotations.toList() diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt index 7d3f766039..018b289557 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.ast +import io.kotlintest.shouldBe import net.sourceforge.pmd.lang.ast.test.shouldBe import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType @@ -52,7 +53,7 @@ class ASTConstructorDeclarationTest : ParserTestSpec({ } } - it::toList shouldBe listOf( + it.toList() shouldBe listOf( child { localVarModifiers { } primitiveType(PrimitiveType.INT) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt index 2a7b399333..929571c1d5 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt @@ -102,7 +102,7 @@ class ASTEnumConstantTest : ParserTestSpec({ val c = it it::getModifiers shouldBe modifiers { - c::getDeclaredAnnotations shouldBe listOf(annotation("C")) + c::declaredAnnotationsList shouldBe listOf(annotation("C")) } @@ -118,7 +118,7 @@ class ASTEnumConstantTest : ParserTestSpec({ val c = it it::getModifiers shouldBe modifiers { - c::getDeclaredAnnotations shouldBe listOf(annotation("A"), annotation("a")) + c::declaredAnnotationsList shouldBe listOf(annotation("A"), annotation("a")) } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt index c2f6373742..6b6786b3d7 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt @@ -1,6 +1,7 @@ package net.sourceforge.pmd.lang.java.ast import io.kotlintest.should +import io.kotlintest.shouldBe import io.kotlintest.shouldNot import net.sourceforge.pmd.lang.ast.test.shouldBe import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType @@ -399,7 +400,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({ it::getResultType shouldBe voidResult() it::getFormalParameters shouldBe formalsList(0) { - it::toList shouldBe emptyList() + it.toList() shouldBe emptyList() it::getReceiverParameter shouldBe child { classType("Foo") { @@ -434,7 +435,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({ } } - it::toList shouldBe listOf( + it.toList() shouldBe listOf( child { localVarModifiers { } primitiveType(PrimitiveType.INT) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt index c2367a45e8..0a99fc9db0 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt @@ -472,8 +472,14 @@ fun TreeNodeWrapper.ambiguousName(image: String, contents: NodeSpec.memberValuePair(name: String, contents: ValuedNodeSpec) = child { - it::getMemberName shouldBe name - it::getMemberValue shouldBe contents() + it::getName shouldBe name + it::getValue shouldBe contents() + } + +fun TreeNodeWrapper.shorthandMemberValue(contents: ValuedNodeSpec) = + memberValuePair("value") { + it::isShorthand shouldBe true + contents() }