forked from phoedos/pmd
[java] Add new rule UseEnumCollections
This commit is contained in:
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule.bestpractices;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
|
||||
import net.sourceforge.pmd.lang.java.types.JClassType;
|
||||
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
|
||||
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
|
||||
|
||||
/**
|
||||
* Detect cases where EnumSet and EnumMap can be used.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class UseEnumCollectionsRule extends AbstractJavaRulechainRule {
|
||||
|
||||
public UseEnumCollectionsRule() {
|
||||
super(ASTConstructorCall.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visit(ASTConstructorCall call, Object data) {
|
||||
JTypeMirror builtType = call.getTypeMirror();
|
||||
|
||||
if (!builtType.isRaw()) {
|
||||
boolean isMap = TypeTestUtil.isExactlyA(HashMap.class, builtType);
|
||||
if (isMap || TypeTestUtil.isExactlyA(HashSet.class, builtType)) {
|
||||
|
||||
List<JTypeMirror> typeArgs = ((JClassType) builtType).getTypeArgs();
|
||||
JTypeDeclSymbol keySymbol = typeArgs.get(0).getSymbol();
|
||||
|
||||
if (keySymbol instanceof JClassSymbol && ((JClassSymbol) keySymbol).isEnum()) {
|
||||
String enumCollectionReplacement = isMap ? "EnumMap" : "EnumSet";
|
||||
asCtx(data).addViolation(call.getTypeNode(), enumCollectionReplacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1723,6 +1723,39 @@ public class Foo {
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
|
||||
<rule name="UseEnumCollections"
|
||||
language="java"
|
||||
since="7.3.0"
|
||||
message="This collection could be an {0}"
|
||||
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UseEnumCollectionsRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useenumcollections">
|
||||
<description>
|
||||
Wherever possible, use `EnumSet` or `EnumMap` instead of `HashSet` and `HashMap` when the keys
|
||||
are of an enum type. This rule reports constructor expressions for hash sets or maps whose key
|
||||
type is an enum type.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
<![CDATA[
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
enum Example {
|
||||
A, B, C;
|
||||
|
||||
public static Set<Example> newSet() {
|
||||
return new HashSet<>(); // Could be EnumSet.noneOf(Example.class)
|
||||
}
|
||||
|
||||
public static <V> Map<Example, V> newMap() {
|
||||
return new HashMap<>(); // Could be new EnumMap<>(Example.class)
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="UseStandardCharsets"
|
||||
language="java"
|
||||
since="6.34.0"
|
||||
|
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule.bestpractices;
|
||||
|
||||
import net.sourceforge.pmd.test.PmdRuleTst;
|
||||
|
||||
class UseEnumCollectionsTest extends PmdRuleTst {
|
||||
// no additional unit tests
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<test-data
|
||||
xmlns="http://pmd.sourceforge.net/rule-tests"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
|
||||
|
||||
<test-code>
|
||||
<description>Use enumset</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>8</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>This collection could be an EnumSet</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
import java.util.*;
|
||||
|
||||
public class Foo {
|
||||
|
||||
enum E {A, B, C}
|
||||
|
||||
public static boolean bar() {
|
||||
Set<E> set = new HashSet<>();
|
||||
return set.contains(E.A);
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
|
||||
|
||||
<test-code>
|
||||
<description>Use enummap</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>7</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>This collection could be an EnumMap</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
import java.util.*;
|
||||
|
||||
public class Foo {
|
||||
public enum E {A, B, C}
|
||||
|
||||
public static Map<E, Boolean> bar() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Neg, LinkedHashSet or LinkedHashMap</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import java.util.*;
|
||||
|
||||
public class Foo {
|
||||
public enum E {A, B, C}
|
||||
|
||||
public static Map<E, Boolean> bar() {
|
||||
Set<E> set = new LinkedHashSet<>();
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
</test-data>
|
Reference in New Issue
Block a user