Merge branch 'pr-1851'

This commit is contained in:
Juan Martín Sotuyo Dodero
2019-06-16 21:44:11 -03:00
3 changed files with 96 additions and 9 deletions

View File

@ -41,6 +41,9 @@ datetime field.
on the method level. To allow the old behavior, the new property `allowMethodLevelSynchronization` can
be enabled.
* The Java rule {% rule "java/design/UseUtilityClass" %} (`java-design`) has a new property `ignoredAnnotations`.
By default, classes that are annotated with Lombok's `@UtilityClass` are ignored now.
### Fixed Issues
* java
@ -48,6 +51,8 @@ datetime field.
* java-bestpractices
* [#1703](https://github.com/pmd/pmd/issues/1703): \[java] UnusedPrivateField on member annotated with lombok @Delegate
* [#1845](https://github.com/pmd/pmd/issues/1845): \[java] Regression in MethodReturnsInternalArray not handling enums
* java-design
* [#1094](https://github.com/pmd/pmd/issues/1094): \[java] UseUtilityClass should be LombokAware
* java-multithreading
* [#1814](https://github.com/pmd/pmd/issues/1814): \[java] UnsynchronizedStaticFormatter documentation and implementation wrong
* [#1815](https://github.com/pmd/pmd/issues/1815): \[java] False negative in UnsynchronizedStaticFormatter

View File

@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.java.rule.design;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
@ -17,24 +19,35 @@ import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTResultType;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.rule.AbstractLombokAwareRule;
public class UseUtilityClassRule extends AbstractJavaRule {
public class UseUtilityClassRule extends AbstractLombokAwareRule {
public UseUtilityClassRule() {
addRuleChainVisit(ASTClassOrInterfaceBody.class);
@Override
protected Collection<String> defaultSuppressionAnnotations() {
return Arrays.asList("lombok.experimental.UtilityClass");
}
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (hasIgnoredAnnotation(node)) {
return data;
}
return super.visit(node, data);
}
@Override
public Object visit(ASTClassOrInterfaceBody decl, Object data) {
Object result = super.visit(decl, data);
if (decl.jjtGetParent() instanceof ASTClassOrInterfaceDeclaration) {
ASTClassOrInterfaceDeclaration parent = (ASTClassOrInterfaceDeclaration) decl.jjtGetParent();
if (parent.isAbstract() || parent.isInterface() || parent.getSuperClassTypeNode() != null) {
return data;
return result;
}
if (isOkUsingLombok(parent)) {
return data;
if (hasLombokNoArgsConstructor(parent)) {
return result;
}
int i = decl.jjtGetNumChildren();
@ -81,10 +94,10 @@ public class UseUtilityClassRule extends AbstractJavaRule {
addViolation(data, decl);
}
}
return data;
return result;
}
private boolean isOkUsingLombok(ASTClassOrInterfaceDeclaration parent) {
private boolean hasLombokNoArgsConstructor(ASTClassOrInterfaceDeclaration parent) {
// check if there's a lombok no arg private constructor, if so skip the rest of the rules
ASTAnnotation annotation = parent.getAnnotation("lombok.NoArgsConstructor");

View File

@ -360,4 +360,73 @@ public class FooLocal extends ThreadLocal<Integer> {
}
]]></code>
</test-code>
<test-code>
<description>#1094 [java] UseUtilityClass should be LombokAware</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import lombok.experimental.UtilityClass;
@UtilityClass
public class MyUtil {
private final static int CONSTANT = 5;
public static int addSomething(int in) {
return in + CONSTANT;
}
}
]]></code>
</test-code>
<test-code>
<description>Inner class in abstract class false-negative</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public abstract class Outer {
private static class Inner {
public static int getInt() { return 42; }
}
}
]]></code>
</test-code>
<test-code>
<description>Inner class in abstract class false-negative</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public abstract class Outer {
private static class Inner {
private static int answer;
public static int getInt() { return answer; }
}
}
]]></code>
</test-code>
<test-code>
<description>Inner class in interface false-negative</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public interface Outer {
private static class Inner {
public static int getInt() { return 42; }
}
}
]]></code>
</test-code>
<test-code>
<description>Inner class in sub-class false-negative</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Outer extends Object {
private static class Inner {
public static boolean isYes(int a) {
return a != 0;
}
}
}
]]></code>
</test-code>
</test-data>