forked from phoedos/pmd
#1420 UnusedPrivateField: Ignore fields if using lombok
This commit is contained in:
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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:**
|
||||
|
||||
|
Reference in New Issue
Block a user