Merge branch 'pr-1851'
This commit is contained in:
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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>
|
||||
|
Reference in New Issue
Block a user