/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.rule; import java.util.HashSet; import java.util.List; import java.util.Set; import net.sourceforge.pmd.lang.ast.Node; 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.ASTImportDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; /** * Base class for rules, that should ignore classes/fields that are annotated * with Lombok annotations. * * @author Andreas Dangel */ public class AbstractLombokAwareRule extends AbstractJavaRule { private boolean lombokImported = false; private boolean classHasLombokAnnotation = false; private static final String LOMBOK_PACKAGE = "lombok"; private static final Set<String> LOMBOK_ANNOTATIONS = new HashSet<>(); static { LOMBOK_ANNOTATIONS.add("Data"); LOMBOK_ANNOTATIONS.add("Getter"); LOMBOK_ANNOTATIONS.add("Setter"); LOMBOK_ANNOTATIONS.add("Value"); LOMBOK_ANNOTATIONS.add("RequiredArgsConstructor"); LOMBOK_ANNOTATIONS.add("AllArgsConstructor"); LOMBOK_ANNOTATIONS.add("Builder"); } @Override public Object visit(ASTCompilationUnit node, Object data) { lombokImported = false; return super.visit(node, data); } @Override public Object visit(ASTImportDeclaration node, Object data) { ASTName name = node.getFirstChildOfType(ASTName.class); if (!lombokImported && name != null && name.getImage() != null & name.getImage().startsWith(LOMBOK_PACKAGE)) { lombokImported = true; } return super.visit(node, data); } @Override public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { classHasLombokAnnotation = hasLombokAnnotation(node); return super.visit(node, data); } /** * Returns whether there have been class level Lombok annotations found. * Note: this can only be queried after the class declaration node has been * processed. * * @return <code>true</code> if a lombok annotation at the class level has * been found */ protected boolean hasClassLombokAnnotation() { return classHasLombokAnnotation; } /** * Checks whether the given node is annotated with any lombok annotation. * The node can be any node, e.g. class declaration or field declaration. * * @param node * the node to check * @return <code>true</code> if a lombok annotation has been found */ protected boolean hasLombokAnnotation(Node node) { boolean result = false; Node parent = node.jjtGetParent(); List<ASTAnnotation> annotations = parent.findChildrenOfType(ASTAnnotation.class); for (ASTAnnotation annotation : annotations) { ASTName name = annotation.getFirstDescendantOfType(ASTName.class); if (name != null) { String annotationName = name.getImage(); if (lombokImported) { if (LOMBOK_ANNOTATIONS.contains(annotationName)) { result = true; } } else { if (annotationName.startsWith(LOMBOK_PACKAGE + ".")) { String shortName = annotationName.substring(LOMBOK_PACKAGE.length() + 1); if (LOMBOK_ANNOTATIONS.contains(shortName)) { result = true; } } } } } return result; } }