#1420 UnusedPrivateField: Ignore fields if using lombok

This commit is contained in:
Andreas Dangel
2015-10-04 09:52:22 +02:00
parent 39d77e849a
commit 39cfbc238b
3 changed files with 139 additions and 2 deletions

View File

@ -4,15 +4,21 @@
package net.sourceforge.pmd.lang.java.rule.unusedcode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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.ASTClassOrInterfaceBody;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTEnumBody;
import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
@ -26,14 +32,44 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
public class UnusedPrivateFieldRule extends AbstractJavaRule {
private boolean lombokImported = false;
private static final String LOMBOK_PACKAGE = "lombok";
private static final Set<String> LOMBOK_ANNOTATIONS = new HashSet<String>();
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) {
boolean classHasLombok = hasLombokAnnotation(node);
Map<VariableNameDeclaration, List<NameOccurrence>> vars = node.getScope().getDeclarations(
VariableNameDeclaration.class);
for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : vars.entrySet()) {
VariableNameDeclaration decl = entry.getKey();
AccessNode accessNodeParent = decl.getAccessNodeParent();
if (!accessNodeParent.isPrivate() || isOK(decl.getImage())) {
if (!accessNodeParent.isPrivate() || isOK(decl.getImage()) || classHasLombok || hasLombokAnnotation(accessNodeParent)) {
continue;
}
if (!actuallyUsed(entry.getValue())) {
@ -45,6 +81,31 @@ public class UnusedPrivateFieldRule extends AbstractJavaRule {
return super.visit(node, data);
}
private 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;
}
private boolean usedInOuterEnum(ASTClassOrInterfaceDeclaration node, NameDeclaration decl) {
List<ASTEnumDeclaration> outerEnums = node.getParentsOfType(ASTEnumDeclaration.class);
for (ASTEnumDeclaration outerEnum : outerEnums) {

View File

@ -459,6 +459,80 @@ public class UnusedPrivateFieldClass
return m_bugTest.m_number == m_number;
}
}
}
]]></code>
</test-code>
<test-code>
<description>#1420 UnusedPrivateField: Ignore fields if using lombok - 1</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
@lombok.Data
public class Foo {
private String bar;
}
]]></code>
</test-code>
<test-code>
<description>#1420 UnusedPrivateField: Ignore fields if using lombok - 2</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import lombok.Data;
@Data
public class Foo {
private String bar;
}
]]></code>
</test-code>
<test-code>
<description>#1420 UnusedPrivateField: Ignore fields if using lombok - 3</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import lombok.*;
@Data
public class Foo {
private String bar;
}
]]></code>
</test-code>
<test-code>
<description>#1420 UnusedPrivateField: Ignore fields if using lombok - 4</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import lombok.Getter;
@Getter
public class Foo {
private String bar;
}
]]></code>
</test-code>
<test-code>
<description>#1420 UnusedPrivateField: Ignore fields if using lombok - 5</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import lombok.Getter;
public class Foo {
@Getter private String bar;
}
]]></code>
</test-code>
<test-code>
<description>#1420 UnusedPrivateField: Ignore fields if using lombok - 6</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import lombok.Getter;
public class Foo {
@Getter(lazy=true) private String bar;
}
]]></code>
</test-code>
<test-code>
<description>#1420 UnusedPrivateField: Ignore fields if using lombok - 7</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
@Data
public class Foo {
private String bar;
}
]]></code>
</test-code>

View File

@ -15,7 +15,7 @@
PMD and CPD Command Line Interfaces have a new optional parameter: `failOnViolation`. Executing PMD with the option
`-failOnViolation false` will perform the PMD checks but won't fail the build and still exit with status 0.
This is useful if you only want to generate the report with violations but don't want to fail your build.
* [#1420](https://sourceforge.net/p/pmd/bugs/1420/): UnusedPrivateField: Ignore fields if using lombok
**New Rules:**
@ -57,6 +57,8 @@
assertEquals, that use Boolean.TRUE/FALSE constants.
* Modified Rule: rulesets/java/basic.xml/CheckResultSet: Do not require to check the result of a navigation
method, if it is returned.
* Modified Rule: rulesets/java/unusedcode.xml/UnusedPrivateField: This rule won't trigger anymore if
[Lombok](https://projectlombok.org) is in use. See [#1420](https://sourceforge.net/p/pmd/bugs/1420/).
**Pull Requests:**